1 1.34 jmcneill /* $NetBSD: acpi_cpu_tstate.c,v 1.34 2020/12/07 10:57:41 jmcneill Exp $ */ 2 1.1 jruoho 3 1.1 jruoho /*- 4 1.1 jruoho * Copyright (c) 2010 Jukka Ruohonen <jruohonen (at) iki.fi> 5 1.1 jruoho * All rights reserved. 6 1.1 jruoho * 7 1.1 jruoho * Redistribution and use in source and binary forms, with or without 8 1.1 jruoho * modification, are permitted provided that the following conditions 9 1.1 jruoho * are met: 10 1.1 jruoho * 11 1.1 jruoho * 1. Redistributions of source code must retain the above copyright 12 1.1 jruoho * notice, this list of conditions and the following disclaimer. 13 1.1 jruoho * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 jruoho * notice, this list of conditions and the following disclaimer in the 15 1.1 jruoho * documentation and/or other materials provided with the distribution. 16 1.1 jruoho * 17 1.1 jruoho * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 1.1 jruoho * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 1.1 jruoho * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 1.1 jruoho * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 1.1 jruoho * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 1.1 jruoho * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 1.1 jruoho * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 1.1 jruoho * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 1.1 jruoho * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 1.1 jruoho * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 1.1 jruoho * SUCH DAMAGE. 28 1.1 jruoho */ 29 1.1 jruoho #include <sys/cdefs.h> 30 1.34 jmcneill __KERNEL_RCSID(0, "$NetBSD: acpi_cpu_tstate.c,v 1.34 2020/12/07 10:57:41 jmcneill Exp $"); 31 1.1 jruoho 32 1.1 jruoho #include <sys/param.h> 33 1.1 jruoho #include <sys/kmem.h> 34 1.24 jruoho #include <sys/xcall.h> 35 1.34 jmcneill #include <sys/cpu.h> 36 1.1 jruoho 37 1.1 jruoho #include <dev/acpi/acpireg.h> 38 1.1 jruoho #include <dev/acpi/acpivar.h> 39 1.1 jruoho #include <dev/acpi/acpi_cpu.h> 40 1.1 jruoho 41 1.1 jruoho #define _COMPONENT ACPI_BUS_COMPONENT 42 1.1 jruoho ACPI_MODULE_NAME ("acpi_cpu_tstate") 43 1.1 jruoho 44 1.1 jruoho static ACPI_STATUS acpicpu_tstate_tss(struct acpicpu_softc *); 45 1.1 jruoho static ACPI_STATUS acpicpu_tstate_tss_add(struct acpicpu_tstate *, 46 1.1 jruoho ACPI_OBJECT *); 47 1.1 jruoho static ACPI_STATUS acpicpu_tstate_ptc(struct acpicpu_softc *); 48 1.23 jruoho static ACPI_STATUS acpicpu_tstate_dep(struct acpicpu_softc *); 49 1.1 jruoho static ACPI_STATUS acpicpu_tstate_fadt(struct acpicpu_softc *); 50 1.1 jruoho static ACPI_STATUS acpicpu_tstate_change(struct acpicpu_softc *); 51 1.13 jruoho static void acpicpu_tstate_reset(struct acpicpu_softc *); 52 1.24 jruoho static void acpicpu_tstate_set_xcall(void *, void *); 53 1.24 jruoho 54 1.24 jruoho extern struct acpicpu_softc **acpicpu_sc; 55 1.1 jruoho 56 1.1 jruoho void 57 1.1 jruoho acpicpu_tstate_attach(device_t self) 58 1.1 jruoho { 59 1.1 jruoho struct acpicpu_softc *sc = device_private(self); 60 1.1 jruoho const char *str; 61 1.12 jruoho ACPI_HANDLE tmp; 62 1.1 jruoho ACPI_STATUS rv; 63 1.1 jruoho 64 1.1 jruoho /* 65 1.5 jruoho * Disable T-states for PIIX4. 66 1.5 jruoho */ 67 1.5 jruoho if ((sc->sc_flags & ACPICPU_FLAG_PIIX4) != 0) 68 1.5 jruoho return; 69 1.5 jruoho 70 1.1 jruoho rv = acpicpu_tstate_tss(sc); 71 1.1 jruoho 72 1.1 jruoho if (ACPI_FAILURE(rv)) { 73 1.1 jruoho str = "_TSS"; 74 1.1 jruoho goto out; 75 1.1 jruoho } 76 1.1 jruoho 77 1.1 jruoho rv = acpicpu_tstate_ptc(sc); 78 1.1 jruoho 79 1.1 jruoho if (ACPI_FAILURE(rv)) { 80 1.1 jruoho str = "_PTC"; 81 1.1 jruoho goto out; 82 1.1 jruoho } 83 1.1 jruoho 84 1.10 jruoho /* 85 1.23 jruoho * Query the optional _TSD. 86 1.23 jruoho */ 87 1.23 jruoho rv = acpicpu_tstate_dep(sc); 88 1.23 jruoho 89 1.23 jruoho if (ACPI_SUCCESS(rv)) 90 1.23 jruoho sc->sc_flags |= ACPICPU_FLAG_T_DEP; 91 1.23 jruoho 92 1.23 jruoho /* 93 1.10 jruoho * Comparable to P-states, the _TPC object may 94 1.10 jruoho * be absent in some systems, even though it is 95 1.10 jruoho * required by ACPI 3.0 along with _TSS and _PTC. 96 1.10 jruoho */ 97 1.12 jruoho rv = AcpiGetHandle(sc->sc_node->ad_handle, "_TPC", &tmp); 98 1.12 jruoho 99 1.12 jruoho if (ACPI_FAILURE(rv)) { 100 1.12 jruoho aprint_debug_dev(self, "_TPC missing\n"); 101 1.12 jruoho rv = AE_OK; 102 1.12 jruoho } 103 1.1 jruoho 104 1.1 jruoho out: 105 1.1 jruoho if (ACPI_FAILURE(rv)) { 106 1.1 jruoho 107 1.1 jruoho if (rv != AE_NOT_FOUND) 108 1.1 jruoho aprint_error_dev(sc->sc_dev, "failed to evaluate " 109 1.1 jruoho "%s: %s\n", str, AcpiFormatException(rv)); 110 1.1 jruoho 111 1.1 jruoho rv = acpicpu_tstate_fadt(sc); 112 1.1 jruoho 113 1.1 jruoho if (ACPI_FAILURE(rv)) 114 1.1 jruoho return; 115 1.1 jruoho 116 1.1 jruoho sc->sc_flags |= ACPICPU_FLAG_T_FADT; 117 1.1 jruoho } 118 1.1 jruoho 119 1.1 jruoho sc->sc_flags |= ACPICPU_FLAG_T; 120 1.1 jruoho 121 1.13 jruoho acpicpu_tstate_reset(sc); 122 1.1 jruoho } 123 1.1 jruoho 124 1.30 jruoho void 125 1.1 jruoho acpicpu_tstate_detach(device_t self) 126 1.1 jruoho { 127 1.1 jruoho struct acpicpu_softc *sc = device_private(self); 128 1.1 jruoho size_t size; 129 1.1 jruoho 130 1.1 jruoho if ((sc->sc_flags & ACPICPU_FLAG_T) == 0) 131 1.30 jruoho return; 132 1.1 jruoho 133 1.1 jruoho size = sc->sc_tstate_count * sizeof(*sc->sc_tstate); 134 1.1 jruoho 135 1.1 jruoho if (sc->sc_tstate != NULL) 136 1.1 jruoho kmem_free(sc->sc_tstate, size); 137 1.1 jruoho 138 1.1 jruoho sc->sc_flags &= ~ACPICPU_FLAG_T; 139 1.1 jruoho } 140 1.1 jruoho 141 1.11 jruoho void 142 1.1 jruoho acpicpu_tstate_start(device_t self) 143 1.1 jruoho { 144 1.11 jruoho /* Nothing. */ 145 1.1 jruoho } 146 1.1 jruoho 147 1.27 jruoho void 148 1.27 jruoho acpicpu_tstate_suspend(void *aux) 149 1.1 jruoho { 150 1.27 jruoho struct acpicpu_softc *sc; 151 1.27 jruoho device_t self = aux; 152 1.27 jruoho 153 1.27 jruoho sc = device_private(self); 154 1.13 jruoho 155 1.14 jruoho mutex_enter(&sc->sc_mtx); 156 1.13 jruoho acpicpu_tstate_reset(sc); 157 1.14 jruoho mutex_exit(&sc->sc_mtx); 158 1.1 jruoho } 159 1.1 jruoho 160 1.27 jruoho void 161 1.27 jruoho acpicpu_tstate_resume(void *aux) 162 1.1 jruoho { 163 1.27 jruoho /* Nothing. */ 164 1.1 jruoho } 165 1.1 jruoho 166 1.1 jruoho void 167 1.1 jruoho acpicpu_tstate_callback(void *aux) 168 1.1 jruoho { 169 1.1 jruoho struct acpicpu_softc *sc; 170 1.1 jruoho device_t self = aux; 171 1.1 jruoho uint32_t omax, omin; 172 1.1 jruoho int i; 173 1.1 jruoho 174 1.1 jruoho sc = device_private(self); 175 1.1 jruoho 176 1.1 jruoho if ((sc->sc_flags & ACPICPU_FLAG_T_FADT) != 0) 177 1.1 jruoho return; 178 1.1 jruoho 179 1.1 jruoho mutex_enter(&sc->sc_mtx); 180 1.1 jruoho 181 1.1 jruoho /* 182 1.1 jruoho * If P-states are in use, we should ignore 183 1.1 jruoho * the interrupt unless we are in the highest 184 1.1 jruoho * P-state (see ACPI 4.0, section 8.4.3.3). 185 1.1 jruoho */ 186 1.1 jruoho if ((sc->sc_flags & ACPICPU_FLAG_P) != 0) { 187 1.1 jruoho 188 1.1 jruoho for (i = sc->sc_pstate_count - 1; i >= 0; i--) { 189 1.1 jruoho 190 1.1 jruoho if (sc->sc_pstate[i].ps_freq != 0) 191 1.1 jruoho break; 192 1.1 jruoho } 193 1.1 jruoho 194 1.1 jruoho if (sc->sc_pstate_current != sc->sc_pstate[i].ps_freq) { 195 1.1 jruoho mutex_exit(&sc->sc_mtx); 196 1.1 jruoho return; 197 1.1 jruoho } 198 1.1 jruoho } 199 1.1 jruoho 200 1.1 jruoho omax = sc->sc_tstate_max; 201 1.1 jruoho omin = sc->sc_tstate_min; 202 1.1 jruoho 203 1.1 jruoho (void)acpicpu_tstate_change(sc); 204 1.1 jruoho 205 1.1 jruoho if (omax != sc->sc_tstate_max || omin != sc->sc_tstate_min) { 206 1.1 jruoho 207 1.1 jruoho aprint_debug_dev(sc->sc_dev, "throttling window " 208 1.1 jruoho "changed from %u-%u %% to %u-%u %%\n", 209 1.1 jruoho sc->sc_tstate[omax].ts_percent, 210 1.1 jruoho sc->sc_tstate[omin].ts_percent, 211 1.1 jruoho sc->sc_tstate[sc->sc_tstate_max].ts_percent, 212 1.1 jruoho sc->sc_tstate[sc->sc_tstate_min].ts_percent); 213 1.1 jruoho } 214 1.1 jruoho 215 1.1 jruoho mutex_exit(&sc->sc_mtx); 216 1.1 jruoho } 217 1.1 jruoho 218 1.1 jruoho static ACPI_STATUS 219 1.1 jruoho acpicpu_tstate_tss(struct acpicpu_softc *sc) 220 1.1 jruoho { 221 1.1 jruoho struct acpicpu_tstate *ts; 222 1.1 jruoho ACPI_OBJECT *obj; 223 1.1 jruoho ACPI_BUFFER buf; 224 1.1 jruoho ACPI_STATUS rv; 225 1.1 jruoho uint32_t count; 226 1.1 jruoho uint32_t i, j; 227 1.1 jruoho 228 1.1 jruoho rv = acpi_eval_struct(sc->sc_node->ad_handle, "_TSS", &buf); 229 1.1 jruoho 230 1.1 jruoho if (ACPI_FAILURE(rv)) 231 1.1 jruoho return rv; 232 1.1 jruoho 233 1.1 jruoho obj = buf.Pointer; 234 1.1 jruoho 235 1.1 jruoho if (obj->Type != ACPI_TYPE_PACKAGE) { 236 1.1 jruoho rv = AE_TYPE; 237 1.1 jruoho goto out; 238 1.1 jruoho } 239 1.1 jruoho 240 1.1 jruoho sc->sc_tstate_count = obj->Package.Count; 241 1.1 jruoho 242 1.1 jruoho if (sc->sc_tstate_count == 0) { 243 1.1 jruoho rv = AE_NOT_EXIST; 244 1.1 jruoho goto out; 245 1.1 jruoho } 246 1.1 jruoho 247 1.1 jruoho sc->sc_tstate = kmem_zalloc(sc->sc_tstate_count * 248 1.1 jruoho sizeof(struct acpicpu_tstate), KM_SLEEP); 249 1.1 jruoho 250 1.1 jruoho if (sc->sc_tstate == NULL) { 251 1.1 jruoho rv = AE_NO_MEMORY; 252 1.1 jruoho goto out; 253 1.1 jruoho } 254 1.1 jruoho 255 1.1 jruoho for (count = i = 0; i < sc->sc_tstate_count; i++) { 256 1.1 jruoho 257 1.1 jruoho ts = &sc->sc_tstate[i]; 258 1.1 jruoho rv = acpicpu_tstate_tss_add(ts, &obj->Package.Elements[i]); 259 1.1 jruoho 260 1.1 jruoho if (ACPI_FAILURE(rv)) { 261 1.1 jruoho ts->ts_percent = 0; 262 1.1 jruoho continue; 263 1.1 jruoho } 264 1.1 jruoho 265 1.1 jruoho for (j = 0; j < i; j++) { 266 1.1 jruoho 267 1.1 jruoho if (ts->ts_percent >= sc->sc_tstate[j].ts_percent) { 268 1.1 jruoho ts->ts_percent = 0; 269 1.1 jruoho break; 270 1.1 jruoho } 271 1.1 jruoho } 272 1.1 jruoho 273 1.1 jruoho if (ts->ts_percent != 0) 274 1.1 jruoho count++; 275 1.1 jruoho } 276 1.1 jruoho 277 1.1 jruoho if (count == 0) { 278 1.1 jruoho rv = AE_NOT_EXIST; 279 1.1 jruoho goto out; 280 1.1 jruoho } 281 1.1 jruoho 282 1.1 jruoho /* 283 1.1 jruoho * There must be an entry with the percent 284 1.1 jruoho * field of 100. If this is not true, and if 285 1.1 jruoho * this entry is not in the expected index, 286 1.1 jruoho * invalidate the use of T-states via _TSS. 287 1.1 jruoho */ 288 1.1 jruoho if (sc->sc_tstate[0].ts_percent != 100) { 289 1.1 jruoho rv = AE_BAD_DECIMAL_CONSTANT; 290 1.1 jruoho goto out; 291 1.1 jruoho } 292 1.1 jruoho 293 1.1 jruoho out: 294 1.1 jruoho if (buf.Pointer != NULL) 295 1.1 jruoho ACPI_FREE(buf.Pointer); 296 1.1 jruoho 297 1.1 jruoho return rv; 298 1.1 jruoho } 299 1.1 jruoho 300 1.1 jruoho static ACPI_STATUS 301 1.1 jruoho acpicpu_tstate_tss_add(struct acpicpu_tstate *ts, ACPI_OBJECT *obj) 302 1.1 jruoho { 303 1.1 jruoho ACPI_OBJECT *elm; 304 1.1 jruoho uint32_t val[5]; 305 1.1 jruoho uint32_t *p; 306 1.1 jruoho int i; 307 1.1 jruoho 308 1.1 jruoho if (obj->Type != ACPI_TYPE_PACKAGE) 309 1.1 jruoho return AE_TYPE; 310 1.1 jruoho 311 1.1 jruoho if (obj->Package.Count != 5) 312 1.1 jruoho return AE_BAD_DATA; 313 1.1 jruoho 314 1.1 jruoho elm = obj->Package.Elements; 315 1.1 jruoho 316 1.1 jruoho for (i = 0; i < 5; i++) { 317 1.1 jruoho 318 1.1 jruoho if (elm[i].Type != ACPI_TYPE_INTEGER) 319 1.1 jruoho return AE_TYPE; 320 1.1 jruoho 321 1.1 jruoho if (elm[i].Integer.Value > UINT32_MAX) 322 1.1 jruoho return AE_AML_NUMERIC_OVERFLOW; 323 1.1 jruoho 324 1.1 jruoho val[i] = elm[i].Integer.Value; 325 1.1 jruoho } 326 1.1 jruoho 327 1.1 jruoho p = &ts->ts_percent; 328 1.1 jruoho 329 1.1 jruoho for (i = 0; i < 5; i++, p++) 330 1.1 jruoho *p = val[i]; 331 1.1 jruoho 332 1.9 jruoho /* 333 1.32 jruoho * The minimum should be either 12.5 % or 6.5 %, 334 1.32 jruoho * the latter 4-bit dynamic range being available 335 1.32 jruoho * in some newer models; see Section 14.5.3.1 in 336 1.32 jruoho * 337 1.32 jruoho * Intel 64 and IA-32 Architectures Software 338 1.32 jruoho * Developer's Manual. Volume 3B, Part 2. 2013. 339 1.9 jruoho */ 340 1.32 jruoho if (ts->ts_percent < 6 || ts->ts_percent > 100) 341 1.1 jruoho return AE_BAD_DECIMAL_CONSTANT; 342 1.1 jruoho 343 1.21 jruoho if (ts->ts_latency == 0 || ts->ts_latency > 1000) 344 1.1 jruoho ts->ts_latency = 1; 345 1.1 jruoho 346 1.1 jruoho return AE_OK; 347 1.1 jruoho } 348 1.1 jruoho 349 1.1 jruoho ACPI_STATUS 350 1.1 jruoho acpicpu_tstate_ptc(struct acpicpu_softc *sc) 351 1.1 jruoho { 352 1.1 jruoho static const size_t size = sizeof(struct acpicpu_reg); 353 1.1 jruoho struct acpicpu_reg *reg[2]; 354 1.1 jruoho ACPI_OBJECT *elm, *obj; 355 1.1 jruoho ACPI_BUFFER buf; 356 1.1 jruoho ACPI_STATUS rv; 357 1.1 jruoho int i; 358 1.1 jruoho 359 1.1 jruoho rv = acpi_eval_struct(sc->sc_node->ad_handle, "_PTC", &buf); 360 1.1 jruoho 361 1.1 jruoho if (ACPI_FAILURE(rv)) 362 1.1 jruoho return rv; 363 1.1 jruoho 364 1.1 jruoho obj = buf.Pointer; 365 1.1 jruoho 366 1.1 jruoho if (obj->Type != ACPI_TYPE_PACKAGE) { 367 1.1 jruoho rv = AE_TYPE; 368 1.1 jruoho goto out; 369 1.1 jruoho } 370 1.1 jruoho 371 1.1 jruoho if (obj->Package.Count != 2) { 372 1.1 jruoho rv = AE_LIMIT; 373 1.1 jruoho goto out; 374 1.1 jruoho } 375 1.1 jruoho 376 1.1 jruoho for (i = 0; i < 2; i++) { 377 1.1 jruoho 378 1.1 jruoho elm = &obj->Package.Elements[i]; 379 1.1 jruoho 380 1.1 jruoho if (elm->Type != ACPI_TYPE_BUFFER) { 381 1.1 jruoho rv = AE_TYPE; 382 1.1 jruoho goto out; 383 1.1 jruoho } 384 1.1 jruoho 385 1.1 jruoho if (size > elm->Buffer.Length) { 386 1.1 jruoho rv = AE_AML_BAD_RESOURCE_LENGTH; 387 1.1 jruoho goto out; 388 1.1 jruoho } 389 1.1 jruoho 390 1.1 jruoho reg[i] = (struct acpicpu_reg *)elm->Buffer.Pointer; 391 1.1 jruoho 392 1.1 jruoho switch (reg[i]->reg_spaceid) { 393 1.1 jruoho 394 1.34 jmcneill case ACPI_ADR_SPACE_SYSTEM_MEMORY: 395 1.34 jmcneill 396 1.34 jmcneill if (reg[i]->reg_addr == 0) { 397 1.34 jmcneill rv = AE_AML_ILLEGAL_ADDRESS; 398 1.34 jmcneill goto out; 399 1.34 jmcneill } 400 1.34 jmcneill 401 1.34 jmcneill break; 402 1.34 jmcneill 403 1.1 jruoho case ACPI_ADR_SPACE_SYSTEM_IO: 404 1.1 jruoho 405 1.1 jruoho if (reg[i]->reg_addr == 0) { 406 1.1 jruoho rv = AE_AML_ILLEGAL_ADDRESS; 407 1.1 jruoho goto out; 408 1.1 jruoho } 409 1.1 jruoho 410 1.34 jmcneill #if defined(__i386__) || defined(__x86_64__) 411 1.1 jruoho /* 412 1.1 jruoho * Check that the values match the IA32 clock 413 1.1 jruoho * modulation MSR, where the bit 0 is reserved, 414 1.1 jruoho * bits 1 through 3 define the duty cycle, and 415 1.1 jruoho * the fourth bit enables the modulation. 416 1.1 jruoho */ 417 1.1 jruoho if (reg[i]->reg_bitwidth != 4) { 418 1.1 jruoho rv = AE_AML_BAD_RESOURCE_VALUE; 419 1.1 jruoho goto out; 420 1.1 jruoho } 421 1.1 jruoho 422 1.1 jruoho if (reg[i]->reg_bitoffset != 1) { 423 1.1 jruoho rv = AE_AML_BAD_RESOURCE_VALUE; 424 1.1 jruoho goto out; 425 1.1 jruoho } 426 1.34 jmcneill #endif 427 1.1 jruoho 428 1.1 jruoho break; 429 1.1 jruoho 430 1.1 jruoho case ACPI_ADR_SPACE_FIXED_HARDWARE: 431 1.1 jruoho 432 1.1 jruoho if ((sc->sc_flags & ACPICPU_FLAG_T_FFH) == 0) { 433 1.1 jruoho rv = AE_SUPPORT; 434 1.1 jruoho goto out; 435 1.1 jruoho } 436 1.1 jruoho 437 1.1 jruoho break; 438 1.1 jruoho 439 1.1 jruoho default: 440 1.1 jruoho rv = AE_AML_INVALID_SPACE_ID; 441 1.1 jruoho goto out; 442 1.1 jruoho } 443 1.1 jruoho } 444 1.1 jruoho 445 1.1 jruoho if (reg[0]->reg_spaceid != reg[1]->reg_spaceid) { 446 1.1 jruoho rv = AE_AML_INVALID_SPACE_ID; 447 1.1 jruoho goto out; 448 1.1 jruoho } 449 1.1 jruoho 450 1.1 jruoho (void)memcpy(&sc->sc_tstate_control, reg[0], size); 451 1.1 jruoho (void)memcpy(&sc->sc_tstate_status, reg[1], size); 452 1.1 jruoho 453 1.1 jruoho out: 454 1.1 jruoho if (buf.Pointer != NULL) 455 1.1 jruoho ACPI_FREE(buf.Pointer); 456 1.1 jruoho 457 1.1 jruoho return rv; 458 1.1 jruoho } 459 1.1 jruoho 460 1.1 jruoho static ACPI_STATUS 461 1.23 jruoho acpicpu_tstate_dep(struct acpicpu_softc *sc) 462 1.23 jruoho { 463 1.23 jruoho ACPI_OBJECT *elm, *obj; 464 1.23 jruoho ACPI_BUFFER buf; 465 1.23 jruoho ACPI_STATUS rv; 466 1.23 jruoho uint32_t val; 467 1.23 jruoho uint8_t i, n; 468 1.23 jruoho 469 1.23 jruoho rv = acpi_eval_struct(sc->sc_node->ad_handle, "_TSD", &buf); 470 1.23 jruoho 471 1.23 jruoho if (ACPI_FAILURE(rv)) 472 1.23 jruoho goto out; 473 1.23 jruoho 474 1.23 jruoho obj = buf.Pointer; 475 1.23 jruoho 476 1.23 jruoho if (obj->Type != ACPI_TYPE_PACKAGE) { 477 1.23 jruoho rv = AE_TYPE; 478 1.23 jruoho goto out; 479 1.23 jruoho } 480 1.23 jruoho 481 1.23 jruoho if (obj->Package.Count != 1) { 482 1.23 jruoho rv = AE_LIMIT; 483 1.23 jruoho goto out; 484 1.23 jruoho } 485 1.23 jruoho 486 1.23 jruoho elm = &obj->Package.Elements[0]; 487 1.23 jruoho 488 1.23 jruoho if (obj->Type != ACPI_TYPE_PACKAGE) { 489 1.23 jruoho rv = AE_TYPE; 490 1.23 jruoho goto out; 491 1.23 jruoho } 492 1.23 jruoho 493 1.23 jruoho n = elm->Package.Count; 494 1.23 jruoho 495 1.23 jruoho if (n != 5) { 496 1.23 jruoho rv = AE_LIMIT; 497 1.23 jruoho goto out; 498 1.23 jruoho } 499 1.23 jruoho 500 1.23 jruoho elm = elm->Package.Elements; 501 1.23 jruoho 502 1.23 jruoho for (i = 0; i < n; i++) { 503 1.23 jruoho 504 1.23 jruoho if (elm[i].Type != ACPI_TYPE_INTEGER) { 505 1.23 jruoho rv = AE_TYPE; 506 1.23 jruoho goto out; 507 1.23 jruoho } 508 1.23 jruoho 509 1.23 jruoho if (elm[i].Integer.Value > UINT32_MAX) { 510 1.23 jruoho rv = AE_AML_NUMERIC_OVERFLOW; 511 1.23 jruoho goto out; 512 1.23 jruoho } 513 1.23 jruoho } 514 1.23 jruoho 515 1.23 jruoho val = elm[1].Integer.Value; 516 1.23 jruoho 517 1.23 jruoho if (val != 0) 518 1.23 jruoho aprint_debug_dev(sc->sc_dev, "invalid revision in _TSD\n"); 519 1.23 jruoho 520 1.23 jruoho val = elm[3].Integer.Value; 521 1.23 jruoho 522 1.23 jruoho if (val < ACPICPU_DEP_SW_ALL || val > ACPICPU_DEP_HW_ALL) { 523 1.23 jruoho rv = AE_AML_BAD_RESOURCE_VALUE; 524 1.23 jruoho goto out; 525 1.23 jruoho } 526 1.23 jruoho 527 1.23 jruoho val = elm[4].Integer.Value; 528 1.23 jruoho 529 1.23 jruoho if (val > sc->sc_ncpus) { 530 1.23 jruoho rv = AE_BAD_VALUE; 531 1.23 jruoho goto out; 532 1.23 jruoho } 533 1.23 jruoho 534 1.23 jruoho sc->sc_tstate_dep.dep_domain = elm[2].Integer.Value; 535 1.23 jruoho sc->sc_tstate_dep.dep_type = elm[3].Integer.Value; 536 1.23 jruoho sc->sc_tstate_dep.dep_ncpus = elm[4].Integer.Value; 537 1.23 jruoho 538 1.23 jruoho out: 539 1.23 jruoho if (ACPI_FAILURE(rv) && rv != AE_NOT_FOUND) 540 1.23 jruoho aprint_debug_dev(sc->sc_dev, "failed to evaluate " 541 1.23 jruoho "_TSD: %s\n", AcpiFormatException(rv)); 542 1.23 jruoho 543 1.23 jruoho if (buf.Pointer != NULL) 544 1.23 jruoho ACPI_FREE(buf.Pointer); 545 1.23 jruoho 546 1.23 jruoho return rv; 547 1.23 jruoho } 548 1.23 jruoho 549 1.23 jruoho static ACPI_STATUS 550 1.1 jruoho acpicpu_tstate_fadt(struct acpicpu_softc *sc) 551 1.1 jruoho { 552 1.1 jruoho static const size_t size = sizeof(struct acpicpu_tstate); 553 1.1 jruoho const uint8_t offset = AcpiGbl_FADT.DutyOffset; 554 1.1 jruoho const uint8_t width = AcpiGbl_FADT.DutyWidth; 555 1.1 jruoho uint8_t beta, count, i; 556 1.1 jruoho 557 1.1 jruoho if (sc->sc_object.ao_pblkaddr == 0) 558 1.1 jruoho return AE_AML_ILLEGAL_ADDRESS; 559 1.1 jruoho 560 1.9 jruoho /* 561 1.22 jruoho * A zero DUTY_WIDTH may be used announce 562 1.22 jruoho * that T-states are not available via FADT 563 1.22 jruoho * (ACPI 4.0, p. 121). See also (section 9.3): 564 1.22 jruoho * 565 1.22 jruoho * Advanced Micro Devices: BIOS and Kernel 566 1.22 jruoho * Developer's Guide for AMD Athlon 64 and 567 1.22 jruoho * AMD Opteron Processors. Revision 3.30, 568 1.22 jruoho * February 2006. 569 1.9 jruoho */ 570 1.1 jruoho if (width == 0 || width + offset > 4) 571 1.1 jruoho return AE_AML_BAD_RESOURCE_VALUE; 572 1.1 jruoho 573 1.1 jruoho count = 1 << width; 574 1.1 jruoho 575 1.1 jruoho if (sc->sc_tstate != NULL) 576 1.1 jruoho kmem_free(sc->sc_tstate, sc->sc_tstate_count * size); 577 1.1 jruoho 578 1.1 jruoho sc->sc_tstate = kmem_zalloc(count * size, KM_SLEEP); 579 1.1 jruoho sc->sc_tstate_count = count; 580 1.1 jruoho 581 1.1 jruoho /* 582 1.1 jruoho * Approximate duty cycles and set the MSR values. 583 1.1 jruoho */ 584 1.1 jruoho for (beta = 100 / count, i = 0; i < count; i++) { 585 1.1 jruoho sc->sc_tstate[i].ts_percent = 100 - beta * i; 586 1.1 jruoho sc->sc_tstate[i].ts_latency = 1; 587 1.1 jruoho } 588 1.1 jruoho 589 1.1 jruoho for (i = 1; i < count; i++) 590 1.1 jruoho sc->sc_tstate[i].ts_control = (count - i) | __BIT(3); 591 1.1 jruoho 592 1.1 jruoho /* 593 1.8 jruoho * Fake values for throttling registers. 594 1.1 jruoho */ 595 1.8 jruoho (void)memset(&sc->sc_tstate_status, 0, sizeof(struct acpicpu_reg)); 596 1.8 jruoho (void)memset(&sc->sc_tstate_control, 0, sizeof(struct acpicpu_reg)); 597 1.8 jruoho 598 1.8 jruoho sc->sc_tstate_status.reg_bitwidth = width; 599 1.8 jruoho sc->sc_tstate_status.reg_bitoffset = offset; 600 1.8 jruoho sc->sc_tstate_status.reg_addr = sc->sc_object.ao_pblkaddr; 601 1.8 jruoho sc->sc_tstate_status.reg_spaceid = ACPI_ADR_SPACE_SYSTEM_IO; 602 1.8 jruoho 603 1.1 jruoho sc->sc_tstate_control.reg_bitwidth = width; 604 1.1 jruoho sc->sc_tstate_control.reg_bitoffset = offset; 605 1.8 jruoho sc->sc_tstate_control.reg_addr = sc->sc_object.ao_pblkaddr; 606 1.7 jruoho sc->sc_tstate_control.reg_spaceid = ACPI_ADR_SPACE_SYSTEM_IO; 607 1.1 jruoho 608 1.1 jruoho return AE_OK; 609 1.1 jruoho } 610 1.1 jruoho 611 1.1 jruoho static ACPI_STATUS 612 1.1 jruoho acpicpu_tstate_change(struct acpicpu_softc *sc) 613 1.1 jruoho { 614 1.1 jruoho ACPI_INTEGER val; 615 1.1 jruoho ACPI_STATUS rv; 616 1.1 jruoho 617 1.13 jruoho acpicpu_tstate_reset(sc); 618 1.1 jruoho 619 1.1 jruoho /* 620 1.1 jruoho * Evaluate the available T-state window: 621 1.1 jruoho * 622 1.1 jruoho * _TPC : either this maximum or any lower power 623 1.1 jruoho * (i.e. higher numbered) state may be used. 624 1.1 jruoho * 625 1.1 jruoho * _TDL : either this minimum or any higher power 626 1.1 jruoho * (i.e. lower numbered) state may be used. 627 1.1 jruoho * 628 1.1 jruoho * _TDL >= _TPC || _TDL >= _TSS[last entry]. 629 1.1 jruoho */ 630 1.1 jruoho rv = acpi_eval_integer(sc->sc_node->ad_handle, "_TPC", &val); 631 1.1 jruoho 632 1.12 jruoho if (ACPI_SUCCESS(rv) && val < sc->sc_tstate_count) { 633 1.1 jruoho 634 1.1 jruoho if (sc->sc_tstate[val].ts_percent != 0) 635 1.1 jruoho sc->sc_tstate_max = val; 636 1.1 jruoho } 637 1.1 jruoho 638 1.1 jruoho rv = acpi_eval_integer(sc->sc_node->ad_handle, "_TDL", &val); 639 1.1 jruoho 640 1.1 jruoho if (ACPI_SUCCESS(rv) && val < sc->sc_tstate_count) { 641 1.1 jruoho 642 1.1 jruoho if (val >= sc->sc_tstate_max && 643 1.1 jruoho sc->sc_tstate[val].ts_percent != 0) 644 1.1 jruoho sc->sc_tstate_min = val; 645 1.1 jruoho } 646 1.1 jruoho 647 1.1 jruoho return AE_OK; 648 1.1 jruoho } 649 1.1 jruoho 650 1.13 jruoho static void 651 1.13 jruoho acpicpu_tstate_reset(struct acpicpu_softc *sc) 652 1.13 jruoho { 653 1.13 jruoho 654 1.13 jruoho sc->sc_tstate_max = 0; 655 1.13 jruoho sc->sc_tstate_min = sc->sc_tstate_count - 1; 656 1.13 jruoho } 657 1.13 jruoho 658 1.1 jruoho int 659 1.24 jruoho acpicpu_tstate_get(struct cpu_info *ci, uint32_t *percent) 660 1.1 jruoho { 661 1.1 jruoho struct acpicpu_tstate *ts = NULL; 662 1.24 jruoho struct acpicpu_softc *sc; 663 1.1 jruoho uint32_t i, val = 0; 664 1.1 jruoho int rv; 665 1.1 jruoho 666 1.24 jruoho sc = acpicpu_sc[ci->ci_acpiid]; 667 1.24 jruoho 668 1.24 jruoho if (__predict_false(sc == NULL)) { 669 1.24 jruoho rv = ENXIO; 670 1.24 jruoho goto fail; 671 1.24 jruoho } 672 1.24 jruoho 673 1.17 jruoho if (__predict_false(sc->sc_cold != false)) { 674 1.1 jruoho rv = EBUSY; 675 1.1 jruoho goto fail; 676 1.1 jruoho } 677 1.1 jruoho 678 1.17 jruoho if (__predict_false((sc->sc_flags & ACPICPU_FLAG_T) == 0)) { 679 1.1 jruoho rv = ENODEV; 680 1.1 jruoho goto fail; 681 1.1 jruoho } 682 1.1 jruoho 683 1.1 jruoho mutex_enter(&sc->sc_mtx); 684 1.1 jruoho 685 1.1 jruoho if (sc->sc_tstate_current != ACPICPU_T_STATE_UNKNOWN) { 686 1.1 jruoho *percent = sc->sc_tstate_current; 687 1.1 jruoho mutex_exit(&sc->sc_mtx); 688 1.1 jruoho return 0; 689 1.1 jruoho } 690 1.1 jruoho 691 1.1 jruoho mutex_exit(&sc->sc_mtx); 692 1.1 jruoho 693 1.24 jruoho switch (sc->sc_tstate_status.reg_spaceid) { 694 1.1 jruoho 695 1.1 jruoho case ACPI_ADR_SPACE_FIXED_HARDWARE: 696 1.1 jruoho 697 1.1 jruoho rv = acpicpu_md_tstate_get(sc, percent); 698 1.1 jruoho 699 1.17 jruoho if (__predict_false(rv != 0)) 700 1.1 jruoho goto fail; 701 1.1 jruoho 702 1.1 jruoho break; 703 1.1 jruoho 704 1.1 jruoho case ACPI_ADR_SPACE_SYSTEM_IO: 705 1.34 jmcneill case ACPI_ADR_SPACE_SYSTEM_MEMORY: 706 1.1 jruoho 707 1.34 jmcneill val = acpicpu_readreg(&sc->sc_tstate_status); 708 1.1 jruoho 709 1.1 jruoho for (i = 0; i < sc->sc_tstate_count; i++) { 710 1.1 jruoho 711 1.1 jruoho if (sc->sc_tstate[i].ts_percent == 0) 712 1.1 jruoho continue; 713 1.1 jruoho 714 1.1 jruoho if (val == sc->sc_tstate[i].ts_status) { 715 1.1 jruoho ts = &sc->sc_tstate[i]; 716 1.1 jruoho break; 717 1.1 jruoho } 718 1.1 jruoho } 719 1.1 jruoho 720 1.17 jruoho if (ts == NULL) { 721 1.1 jruoho rv = EIO; 722 1.1 jruoho goto fail; 723 1.1 jruoho } 724 1.1 jruoho 725 1.1 jruoho *percent = ts->ts_percent; 726 1.1 jruoho break; 727 1.1 jruoho 728 1.1 jruoho default: 729 1.1 jruoho rv = ENOTTY; 730 1.1 jruoho goto fail; 731 1.1 jruoho } 732 1.1 jruoho 733 1.1 jruoho mutex_enter(&sc->sc_mtx); 734 1.1 jruoho sc->sc_tstate_current = *percent; 735 1.1 jruoho mutex_exit(&sc->sc_mtx); 736 1.1 jruoho 737 1.1 jruoho return 0; 738 1.1 jruoho 739 1.1 jruoho fail: 740 1.29 jruoho aprint_error_dev(sc->sc_dev, "failed " 741 1.1 jruoho "to get T-state (err %d)\n", rv); 742 1.1 jruoho 743 1.1 jruoho mutex_enter(&sc->sc_mtx); 744 1.1 jruoho *percent = sc->sc_tstate_current = ACPICPU_T_STATE_UNKNOWN; 745 1.1 jruoho mutex_exit(&sc->sc_mtx); 746 1.1 jruoho 747 1.1 jruoho return rv; 748 1.1 jruoho } 749 1.1 jruoho 750 1.24 jruoho void 751 1.24 jruoho acpicpu_tstate_set(struct cpu_info *ci, uint32_t percent) 752 1.24 jruoho { 753 1.24 jruoho uint64_t xc; 754 1.24 jruoho 755 1.24 jruoho xc = xc_broadcast(0, acpicpu_tstate_set_xcall, &percent, NULL); 756 1.24 jruoho xc_wait(xc); 757 1.24 jruoho } 758 1.24 jruoho 759 1.24 jruoho static void 760 1.24 jruoho acpicpu_tstate_set_xcall(void *arg1, void *arg2) 761 1.1 jruoho { 762 1.1 jruoho struct acpicpu_tstate *ts = NULL; 763 1.24 jruoho struct cpu_info *ci = curcpu(); 764 1.24 jruoho struct acpicpu_softc *sc; 765 1.24 jruoho uint32_t i, percent, val; 766 1.1 jruoho int rv; 767 1.1 jruoho 768 1.24 jruoho percent = *(uint32_t *)arg1; 769 1.24 jruoho sc = acpicpu_sc[ci->ci_acpiid]; 770 1.24 jruoho 771 1.24 jruoho if (__predict_false(sc == NULL)) { 772 1.24 jruoho rv = ENXIO; 773 1.24 jruoho goto fail; 774 1.24 jruoho } 775 1.24 jruoho 776 1.17 jruoho if (__predict_false(sc->sc_cold != false)) { 777 1.1 jruoho rv = EBUSY; 778 1.1 jruoho goto fail; 779 1.1 jruoho } 780 1.1 jruoho 781 1.17 jruoho if (__predict_false((sc->sc_flags & ACPICPU_FLAG_T) == 0)) { 782 1.1 jruoho rv = ENODEV; 783 1.1 jruoho goto fail; 784 1.1 jruoho } 785 1.1 jruoho 786 1.1 jruoho mutex_enter(&sc->sc_mtx); 787 1.1 jruoho 788 1.15 jruoho if (sc->sc_tstate_current == percent) { 789 1.15 jruoho mutex_exit(&sc->sc_mtx); 790 1.24 jruoho return; 791 1.15 jruoho } 792 1.15 jruoho 793 1.1 jruoho for (i = sc->sc_tstate_max; i <= sc->sc_tstate_min; i++) { 794 1.1 jruoho 795 1.17 jruoho if (__predict_false(sc->sc_tstate[i].ts_percent == 0)) 796 1.1 jruoho continue; 797 1.1 jruoho 798 1.1 jruoho if (sc->sc_tstate[i].ts_percent == percent) { 799 1.1 jruoho ts = &sc->sc_tstate[i]; 800 1.1 jruoho break; 801 1.1 jruoho } 802 1.1 jruoho } 803 1.1 jruoho 804 1.1 jruoho mutex_exit(&sc->sc_mtx); 805 1.1 jruoho 806 1.1 jruoho if (__predict_false(ts == NULL)) { 807 1.1 jruoho rv = EINVAL; 808 1.1 jruoho goto fail; 809 1.1 jruoho } 810 1.1 jruoho 811 1.24 jruoho switch (sc->sc_tstate_control.reg_spaceid) { 812 1.1 jruoho 813 1.1 jruoho case ACPI_ADR_SPACE_FIXED_HARDWARE: 814 1.1 jruoho 815 1.1 jruoho rv = acpicpu_md_tstate_set(ts); 816 1.1 jruoho 817 1.17 jruoho if (__predict_false(rv != 0)) 818 1.1 jruoho goto fail; 819 1.1 jruoho 820 1.1 jruoho break; 821 1.1 jruoho 822 1.1 jruoho case ACPI_ADR_SPACE_SYSTEM_IO: 823 1.34 jmcneill case ACPI_ADR_SPACE_SYSTEM_MEMORY: 824 1.1 jruoho 825 1.34 jmcneill acpicpu_writereg(&sc->sc_tstate_control, ts->ts_control); 826 1.1 jruoho 827 1.1 jruoho /* 828 1.1 jruoho * If the status field is zero, the transition is 829 1.1 jruoho * specified to be "asynchronous" and there is no 830 1.1 jruoho * need to check the status (ACPI 4.0, 8.4.3.2). 831 1.1 jruoho */ 832 1.1 jruoho if (ts->ts_status == 0) 833 1.1 jruoho break; 834 1.1 jruoho 835 1.34 jmcneill for (i = 0; i < ACPICPU_T_STATE_RETRY; i++) { 836 1.1 jruoho 837 1.34 jmcneill val = acpicpu_readreg(&sc->sc_tstate_status); 838 1.1 jruoho 839 1.1 jruoho if (val == ts->ts_status) 840 1.1 jruoho break; 841 1.1 jruoho 842 1.1 jruoho DELAY(ts->ts_latency); 843 1.1 jruoho } 844 1.1 jruoho 845 1.1 jruoho if (i == ACPICPU_T_STATE_RETRY) { 846 1.1 jruoho rv = EAGAIN; 847 1.1 jruoho goto fail; 848 1.1 jruoho } 849 1.1 jruoho 850 1.1 jruoho break; 851 1.1 jruoho 852 1.1 jruoho default: 853 1.1 jruoho rv = ENOTTY; 854 1.1 jruoho goto fail; 855 1.1 jruoho } 856 1.1 jruoho 857 1.2 jruoho mutex_enter(&sc->sc_mtx); 858 1.1 jruoho ts->ts_evcnt.ev_count++; 859 1.1 jruoho sc->sc_tstate_current = percent; 860 1.1 jruoho mutex_exit(&sc->sc_mtx); 861 1.1 jruoho 862 1.24 jruoho return; 863 1.1 jruoho 864 1.1 jruoho fail: 865 1.29 jruoho if (rv != EINVAL) 866 1.29 jruoho aprint_error_dev(sc->sc_dev, "failed to " 867 1.29 jruoho "throttle to %u %% (err %d)\n", percent, rv); 868 1.1 jruoho 869 1.1 jruoho mutex_enter(&sc->sc_mtx); 870 1.1 jruoho sc->sc_tstate_current = ACPICPU_T_STATE_UNKNOWN; 871 1.1 jruoho mutex_exit(&sc->sc_mtx); 872 1.1 jruoho } 873