1 /* $OpenBSD: acpicpu.c,v 1.60 2014/07/12 18:48:17 tedu Exp $ */ 2 /* 3 * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/proc.h> 20 #include <sys/signalvar.h> 21 #include <sys/sysctl.h> 22 #include <sys/systm.h> 23 #include <sys/device.h> 24 #include <sys/malloc.h> 25 #include <sys/queue.h> 26 27 #include <machine/bus.h> 28 #include <machine/cpu.h> 29 #include <machine/cpufunc.h> 30 #include <machine/specialreg.h> 31 32 #include <dev/acpi/acpireg.h> 33 #include <dev/acpi/acpivar.h> 34 #include <dev/acpi/acpidev.h> 35 #include <dev/acpi/amltypes.h> 36 #include <dev/acpi/dsdt.h> 37 38 #include <sys/sensors.h> 39 40 int acpicpu_match(struct device *, void *, void *); 41 void acpicpu_attach(struct device *, struct device *, void *); 42 int acpicpu_notify(struct aml_node *, int, void *); 43 void acpicpu_setperf(int); 44 void acpicpu_setperf_ppc_change(struct acpicpu_pss *, int); 45 46 #define ACPI_STATE_C0 0x00 47 #define ACPI_STATE_C1 0x01 48 #define ACPI_STATE_C2 0x02 49 #define ACPI_STATE_C3 0x03 50 51 #define ACPI_PDC_REVID 0x1 52 #define ACPI_PDC_SMP 0xa 53 #define ACPI_PDC_MSR 0x1 54 55 /* _PDC Intel capabilities flags from linux */ 56 #define ACPI_PDC_P_FFH 0x0001 57 #define ACPI_PDC_C_C1_HALT 0x0002 58 #define ACPI_PDC_T_FFH 0x0004 59 #define ACPI_PDC_SMP_C1PT 0x0008 60 #define ACPI_PDC_SMP_C2C3 0x0010 61 #define ACPI_PDC_SMP_P_SWCOORD 0x0020 62 #define ACPI_PDC_SMP_C_SWCOORD 0x0040 63 #define ACPI_PDC_SMP_T_SWCOORD 0x0080 64 #define ACPI_PDC_C_C1_FFH 0x0100 65 #define ACPI_PDC_C_C2C3_FFH 0x0200 66 67 #define FLAGS_NO_C2 0x01 68 #define FLAGS_NO_C3 0x02 69 #define FLAGS_BMCHECK 0x04 70 #define FLAGS_NOTHROTTLE 0x08 71 #define FLAGS_NOPSS 0x10 72 #define FLAGS_NOPCT 0x20 73 74 #define CPU_THT_EN (1L << 4) 75 #define CPU_MAXSTATE(sc) (1L << (sc)->sc_duty_wid) 76 #define CPU_STATE(sc,pct) ((pct * CPU_MAXSTATE(sc) / 100) << (sc)->sc_duty_off) 77 #define CPU_STATEMASK(sc) ((CPU_MAXSTATE(sc) - 1) << (sc)->sc_duty_off) 78 79 #define ACPI_MAX_C2_LATENCY 100 80 #define ACPI_MAX_C3_LATENCY 1000 81 82 /* Make sure throttling bits are valid,a=addr,o=offset,w=width */ 83 #define valid_throttle(o,w,a) (a && w && (o+w)<=31 && (o>4 || (o+w)<=4)) 84 85 struct acpi_cstate 86 { 87 int type; 88 int latency; 89 int power; 90 int address; 91 92 SLIST_ENTRY(acpi_cstate) link; 93 }; 94 95 struct acpicpu_softc { 96 struct device sc_dev; 97 int sc_cpu; 98 99 int sc_duty_wid; 100 int sc_duty_off; 101 int sc_pblk_addr; 102 int sc_pblk_len; 103 int sc_flags; 104 105 SLIST_HEAD(,acpi_cstate) sc_cstates; 106 107 bus_space_tag_t sc_iot; 108 bus_space_handle_t sc_ioh; 109 110 struct acpi_softc *sc_acpi; 111 struct aml_node *sc_devnode; 112 113 int sc_pss_len; 114 int sc_ppc; 115 int sc_level; 116 struct acpicpu_pss *sc_pss; 117 118 struct acpicpu_pct sc_pct; 119 /* save compensation for pct access for lying bios' */ 120 u_int32_t sc_pct_stat_as; 121 u_int32_t sc_pct_ctrl_as; 122 u_int32_t sc_pct_stat_len; 123 u_int32_t sc_pct_ctrl_len; 124 /* 125 * XXX: _PPC Change listener 126 * PPC changes can occur when for example a machine is disconnected 127 * from AC power and can no loger support the highest frequency or 128 * voltage when driven from the battery. 129 * Should probably be reimplemented as a list for now we assume only 130 * one listener 131 */ 132 void (*sc_notify)(struct acpicpu_pss *, int); 133 }; 134 135 void acpicpu_add_cstatepkg(struct aml_value *, void *); 136 int acpicpu_getppc(struct acpicpu_softc *); 137 int acpicpu_getpct(struct acpicpu_softc *); 138 int acpicpu_getpss(struct acpicpu_softc *); 139 struct acpi_cstate *acpicpu_add_cstate(struct acpicpu_softc *, int, int, int, 140 int); 141 void acpicpu_set_pdc(struct acpicpu_softc *); 142 143 #if 0 144 void acpicpu_set_throttle(struct acpicpu_softc *, int); 145 struct acpi_cstate *acpicpu_find_cstate(struct acpicpu_softc *, int); 146 #endif 147 148 struct cfattach acpicpu_ca = { 149 sizeof(struct acpicpu_softc), acpicpu_match, acpicpu_attach 150 }; 151 152 struct cfdriver acpicpu_cd = { 153 NULL, "acpicpu", DV_DULL 154 }; 155 156 extern int setperf_prio; 157 158 struct acpicpu_softc *acpicpu_sc[MAXCPUS]; 159 160 #if 0 161 void 162 acpicpu_set_throttle(struct acpicpu_softc *sc, int level) 163 { 164 uint32_t pbval; 165 166 if (sc->sc_flags & FLAGS_NOTHROTTLE) 167 return; 168 169 /* Disable throttling control */ 170 pbval = inl(sc->sc_pblk_addr); 171 outl(sc->sc_pblk_addr, pbval & ~CPU_THT_EN); 172 if (level < 100) { 173 pbval &= ~CPU_STATEMASK(sc); 174 pbval |= CPU_STATE(sc, level); 175 outl(sc->sc_pblk_addr, pbval & ~CPU_THT_EN); 176 outl(sc->sc_pblk_addr, pbval | CPU_THT_EN); 177 } 178 } 179 180 struct acpi_cstate * 181 acpicpu_find_cstate(struct acpicpu_softc *sc, int type) 182 { 183 struct acpi_cstate *cx; 184 185 SLIST_FOREACH(cx, &sc->sc_cstates, link) 186 if (cx->type == type) 187 return cx; 188 return (NULL); 189 } 190 #endif 191 192 193 void 194 acpicpu_set_pdc(struct acpicpu_softc *sc) 195 { 196 struct aml_value cmd, osc_cmd[4]; 197 struct aml_value res; 198 uint32_t cap; 199 uint32_t buf[3]; 200 201 /* 4077A616-290C-47BE-9EBD-D87058713953 */ 202 static uint8_t cpu_oscuuid[16] = { 0x16, 0xA6, 0x77, 0x40, 0x0C, 0x29, 203 0xBE, 0x47, 0x9E, 0xBD, 0xD8, 0x70, 204 0x58, 0x71, 0x39, 0x53 }; 205 cap = ACPI_PDC_C_C1_HALT | ACPI_PDC_P_FFH | ACPI_PDC_C_C1_FFH 206 | ACPI_PDC_C_C2C3_FFH | ACPI_PDC_SMP_P_SWCOORD | ACPI_PDC_SMP_C2C3 207 | ACPI_PDC_SMP_C1PT; 208 209 if (aml_searchname(sc->sc_devnode, "_OSC")) { 210 /* Query _OSC */ 211 memset(&osc_cmd, 0, sizeof(cmd) * 4); 212 osc_cmd[0].type = AML_OBJTYPE_BUFFER; 213 osc_cmd[0].v_buffer = (uint8_t *)&cpu_oscuuid; 214 osc_cmd[0].length = sizeof(cpu_oscuuid); 215 216 osc_cmd[1].type = AML_OBJTYPE_INTEGER; 217 osc_cmd[1].v_integer = 1; 218 osc_cmd[1].length = 1; 219 220 osc_cmd[2].type = AML_OBJTYPE_INTEGER; 221 osc_cmd[2].v_integer = 2; 222 osc_cmd[2].length = 1; 223 224 buf[0] = 1; 225 buf[1] = cap; 226 osc_cmd[3].type = AML_OBJTYPE_BUFFER; 227 osc_cmd[3].v_buffer = (int8_t *)&buf; 228 osc_cmd[3].length = sizeof(buf); 229 230 aml_evalname(sc->sc_acpi, sc->sc_devnode, "_OSC", 231 4, osc_cmd, &res); 232 233 if (res.type != AML_OBJTYPE_BUFFER || res.length < 8) { 234 printf(": unable to query capabilities\n"); 235 return; 236 } 237 238 /* Evaluate _OSC */ 239 memset(&osc_cmd, 0, sizeof(cmd) * 4); 240 osc_cmd[0].type = AML_OBJTYPE_BUFFER; 241 osc_cmd[0].v_buffer = (uint8_t *)&cpu_oscuuid; 242 osc_cmd[0].length = sizeof(cpu_oscuuid); 243 244 osc_cmd[1].type = AML_OBJTYPE_INTEGER; 245 osc_cmd[1].v_integer = 1; 246 osc_cmd[1].length = 1; 247 248 osc_cmd[2].type = AML_OBJTYPE_INTEGER; 249 osc_cmd[2].v_integer = 2; 250 osc_cmd[2].length = 1; 251 252 buf[0] = 0; 253 buf[1] = (*(uint32_t *)&res.v_buffer[4]) & cap; 254 osc_cmd[3].type = AML_OBJTYPE_BUFFER; 255 osc_cmd[3].v_buffer = (int8_t *)&buf; 256 osc_cmd[3].length = sizeof(buf); 257 258 aml_evalname(sc->sc_acpi, sc->sc_devnode, "_OSC", 259 4, osc_cmd, &res); 260 } else { 261 /* Evaluate _PDC */ 262 memset(&cmd, 0, sizeof(cmd)); 263 cmd.type = AML_OBJTYPE_BUFFER; 264 cmd.v_buffer = (uint8_t *)&buf; 265 cmd.length = sizeof(buf); 266 267 buf[0] = ACPI_PDC_REVID; 268 buf[1] = 1; 269 buf[2] = cap; 270 271 aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PDC", 272 1, &cmd, &res); 273 } 274 } 275 276 277 struct acpi_cstate * 278 acpicpu_add_cstate(struct acpicpu_softc *sc, int type, int latency, int power, 279 int address) 280 { 281 struct acpi_cstate *cx; 282 283 dnprintf(10," C%d: latency:.%4x power:%.4x addr:%.8x\n", 284 type, latency, power, address); 285 286 switch (type) { 287 case ACPI_STATE_C2: 288 if (latency > ACPI_MAX_C2_LATENCY || !address || 289 (sc->sc_flags & FLAGS_NO_C2)) 290 goto bad; 291 break; 292 case ACPI_STATE_C3: 293 if (latency > ACPI_MAX_C3_LATENCY || !address || 294 (sc->sc_flags & FLAGS_NO_C3)) 295 goto bad; 296 break; 297 } 298 299 cx = malloc(sizeof(*cx), M_DEVBUF, M_WAITOK | M_ZERO); 300 301 cx->type = type; 302 cx->power = power; 303 cx->latency = latency; 304 cx->address = address; 305 306 SLIST_INSERT_HEAD(&sc->sc_cstates, cx, link); 307 308 return (cx); 309 bad: 310 dprintf("acpicpu%d: C%d not supported", sc->sc_cpu, type); 311 return (NULL); 312 } 313 314 /* Found a _CST object, add new cstate for each entry */ 315 void 316 acpicpu_add_cstatepkg(struct aml_value *val, void *arg) 317 { 318 struct acpicpu_softc *sc = arg; 319 320 #if defined(ACPI_DEBUG) && !defined(SMALL_KERNEL) 321 aml_showvalue(val, 0); 322 #endif 323 if (val->type != AML_OBJTYPE_PACKAGE || val->length != 4) 324 return; 325 326 acpicpu_add_cstate(sc, val->v_package[1]->v_integer, 327 val->v_package[2]->v_integer, 328 val->v_package[3]->v_integer, -1); 329 } 330 331 332 int 333 acpicpu_match(struct device *parent, void *match, void *aux) 334 { 335 struct acpi_attach_args *aa = aux; 336 struct cfdata *cf = match; 337 338 /* sanity */ 339 if (aa->aaa_name == NULL || 340 strcmp(aa->aaa_name, cf->cf_driver->cd_name) != 0 || 341 aa->aaa_table != NULL) 342 return (0); 343 344 return (1); 345 } 346 347 void 348 acpicpu_attach(struct device *parent, struct device *self, void *aux) 349 { 350 struct acpicpu_softc *sc = (struct acpicpu_softc *)self; 351 struct acpi_attach_args *aa = aux; 352 struct aml_value res; 353 int i; 354 struct acpi_cstate *cx; 355 u_int32_t status = 0; 356 357 sc->sc_acpi = (struct acpi_softc *)parent; 358 sc->sc_devnode = aa->aaa_node; 359 acpicpu_sc[sc->sc_dev.dv_unit] = sc; 360 361 SLIST_INIT(&sc->sc_cstates); 362 363 sc->sc_pss = NULL; 364 365 if (aml_evalnode(sc->sc_acpi, sc->sc_devnode, 0, NULL, &res) == 0) { 366 if (res.type == AML_OBJTYPE_PROCESSOR) { 367 sc->sc_cpu = res.v_processor.proc_id; 368 sc->sc_pblk_addr = res.v_processor.proc_addr; 369 sc->sc_pblk_len = res.v_processor.proc_len; 370 } 371 aml_freevalue(&res); 372 } 373 sc->sc_duty_off = sc->sc_acpi->sc_fadt->duty_offset; 374 sc->sc_duty_wid = sc->sc_acpi->sc_fadt->duty_width; 375 376 acpicpu_set_pdc(sc); 377 378 if (!valid_throttle(sc->sc_duty_off, sc->sc_duty_wid, sc->sc_pblk_addr)) 379 sc->sc_flags |= FLAGS_NOTHROTTLE; 380 #ifdef ACPI_DEBUG 381 printf(": %s: ", sc->sc_devnode->name); 382 printf("\n: hdr:%x pblk:%x,%x duty:%x,%x pstate:%x " 383 "(%ld throttling states)\n", sc->sc_acpi->sc_fadt->hdr_revision, 384 sc->sc_pblk_addr, sc->sc_pblk_len, sc->sc_duty_off, 385 sc->sc_duty_wid, sc->sc_acpi->sc_fadt->pstate_cnt, 386 CPU_MAXSTATE(sc)); 387 #endif 388 389 /* Get C-States from _CST or FADT */ 390 if (!aml_evalname(sc->sc_acpi, sc->sc_devnode, "_CST", 0, NULL, &res)) { 391 aml_foreachpkg(&res, 1, acpicpu_add_cstatepkg, sc); 392 aml_freevalue(&res); 393 } 394 else { 395 /* Some systems don't export a full PBLK reduce functionality */ 396 if (sc->sc_pblk_len < 5) 397 sc->sc_flags |= FLAGS_NO_C2; 398 if (sc->sc_pblk_len < 6) 399 sc->sc_flags |= FLAGS_NO_C3; 400 acpicpu_add_cstate(sc, ACPI_STATE_C2, 401 sc->sc_acpi->sc_fadt->p_lvl2_lat, -1, 402 sc->sc_pblk_addr + 4); 403 acpicpu_add_cstate(sc, ACPI_STATE_C3, 404 sc->sc_acpi->sc_fadt->p_lvl3_lat, -1, 405 sc->sc_pblk_addr + 5); 406 } 407 if (acpicpu_getpss(sc)) { 408 sc->sc_flags |= FLAGS_NOPSS; 409 } else { 410 #ifdef ACPI_DEBUG 411 for (i = 0; i < sc->sc_pss_len; i++) { 412 dnprintf(20, "%d %d %d %d %d %d\n", 413 sc->sc_pss[i].pss_core_freq, 414 sc->sc_pss[i].pss_power, 415 sc->sc_pss[i].pss_trans_latency, 416 sc->sc_pss[i].pss_bus_latency, 417 sc->sc_pss[i].pss_ctrl, 418 sc->sc_pss[i].pss_status); 419 } 420 dnprintf(20, "\n"); 421 #endif 422 if (sc->sc_pss_len == 0) { 423 /* this should never happen */ 424 printf("%s: invalid _PSS length\n", DEVNAME(sc)); 425 sc->sc_flags |= FLAGS_NOPSS; 426 } 427 428 acpicpu_getppc(sc); 429 if (acpicpu_getpct(sc)) 430 sc->sc_flags |= FLAGS_NOPCT; 431 else if (sc->sc_pss_len > 0) { 432 /* Notify BIOS we are handing p-states */ 433 if (sc->sc_acpi->sc_fadt->pstate_cnt) 434 acpi_write_pmreg(sc->sc_acpi, ACPIREG_SMICMD, 0, 435 sc->sc_acpi->sc_fadt->pstate_cnt); 436 437 aml_register_notify(sc->sc_devnode, NULL, 438 acpicpu_notify, sc, ACPIDEV_NOPOLL); 439 440 acpi_gasio(sc->sc_acpi, ACPI_IOREAD, 441 sc->sc_pct.pct_status.grd_gas.address_space_id, 442 sc->sc_pct.pct_status.grd_gas.address, 443 sc->sc_pct_stat_as, sc->sc_pct_stat_as, &status); 444 sc->sc_level = (100 / sc->sc_pss_len) * 445 (sc->sc_pss_len - status); 446 dnprintf(20, "%s: cpu index %d, percentage %d\n", 447 DEVNAME(sc), status, sc->sc_level); 448 if (setperf_prio < 30) { 449 cpu_setperf = acpicpu_setperf; 450 acpicpu_set_notify(acpicpu_setperf_ppc_change); 451 setperf_prio = 30; 452 acpi_hasprocfvs = 1; 453 } 454 } 455 } 456 457 /* 458 * Nicely enumerate what power management capabilities 459 * ACPI CPU provides. 460 */ 461 if (!SLIST_EMPTY(&sc->sc_cstates)) { 462 printf(":"); 463 464 i = 0; 465 SLIST_FOREACH(cx, &sc->sc_cstates, link) { 466 if (i++) 467 printf(","); 468 switch (cx->type) { 469 case ACPI_STATE_C0: 470 printf(" C0"); 471 break; 472 case ACPI_STATE_C1: 473 printf(" C1"); 474 break; 475 case ACPI_STATE_C2: 476 printf(" C2"); 477 break; 478 case ACPI_STATE_C3: 479 printf(" C3"); 480 break; 481 } 482 } 483 } 484 485 if (!(sc->sc_flags & (FLAGS_NOPSS | FLAGS_NOPCT)) || 486 !(sc->sc_flags & FLAGS_NOPSS)) { 487 printf("%c ", SLIST_EMPTY(&sc->sc_cstates) ? ':' : ','); 488 489 /* 490 * If acpicpu is itself providing the capability to transition 491 * states, enumerate them in the fashion that est and powernow 492 * would. 493 */ 494 if (!(sc->sc_flags & (FLAGS_NOPSS | FLAGS_NOPCT))) { 495 printf("FVS, "); 496 for (i = 0; i < sc->sc_pss_len - 1; i++) 497 printf("%d, ", sc->sc_pss[i].pss_core_freq); 498 printf("%d MHz", sc->sc_pss[i].pss_core_freq); 499 } else 500 printf("PSS"); 501 } 502 503 printf("\n"); 504 } 505 506 int 507 acpicpu_getppc(struct acpicpu_softc *sc) 508 { 509 struct aml_value res; 510 511 sc->sc_ppc = 0; 512 513 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PPC", 0, NULL, &res)) { 514 dnprintf(10, "%s: no _PPC\n", DEVNAME(sc)); 515 return (1); 516 } 517 518 sc->sc_ppc = aml_val2int(&res); 519 dnprintf(10, "%s: _PPC: %d\n", DEVNAME(sc), sc->sc_ppc); 520 aml_freevalue(&res); 521 522 return (0); 523 } 524 525 int 526 acpicpu_getpct(struct acpicpu_softc *sc) 527 { 528 struct aml_value res; 529 int rv = 1; 530 531 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PCT", 0, NULL, &res)) { 532 dnprintf(20, "%s: no _PCT\n", DEVNAME(sc)); 533 return (1); 534 } 535 536 if (res.length != 2) { 537 dnprintf(20, "%s: %s: invalid _PCT length\n", DEVNAME(sc), 538 sc->sc_devnode->name); 539 return (1); 540 } 541 542 memcpy(&sc->sc_pct.pct_ctrl, res.v_package[0]->v_buffer, 543 sizeof sc->sc_pct.pct_ctrl); 544 if (sc->sc_pct.pct_ctrl.grd_gas.address_space_id == 545 GAS_FUNCTIONAL_FIXED) { 546 dnprintf(20, "CTRL GASIO is functional fixed hardware.\n"); 547 goto ffh; 548 } 549 550 memcpy(&sc->sc_pct.pct_status, res.v_package[1]->v_buffer, 551 sizeof sc->sc_pct.pct_status); 552 if (sc->sc_pct.pct_status.grd_gas.address_space_id == 553 GAS_FUNCTIONAL_FIXED) { 554 dnprintf(20, "CTRL GASIO is functional fixed hardware.\n"); 555 goto ffh; 556 } 557 558 dnprintf(10, "_PCT(ctrl) : %02x %04x %02x %02x %02x %02x %016llx\n", 559 sc->sc_pct.pct_ctrl.grd_descriptor, 560 sc->sc_pct.pct_ctrl.grd_length, 561 sc->sc_pct.pct_ctrl.grd_gas.address_space_id, 562 sc->sc_pct.pct_ctrl.grd_gas.register_bit_width, 563 sc->sc_pct.pct_ctrl.grd_gas.register_bit_offset, 564 sc->sc_pct.pct_ctrl.grd_gas.access_size, 565 sc->sc_pct.pct_ctrl.grd_gas.address); 566 567 dnprintf(10, "_PCT(status): %02x %04x %02x %02x %02x %02x %016llx\n", 568 sc->sc_pct.pct_status.grd_descriptor, 569 sc->sc_pct.pct_status.grd_length, 570 sc->sc_pct.pct_status.grd_gas.address_space_id, 571 sc->sc_pct.pct_status.grd_gas.register_bit_width, 572 sc->sc_pct.pct_status.grd_gas.register_bit_offset, 573 sc->sc_pct.pct_status.grd_gas.access_size, 574 sc->sc_pct.pct_status.grd_gas.address); 575 576 /* if not set assume single 32 bit access */ 577 sc->sc_pct_stat_as = sc->sc_pct.pct_status.grd_gas.register_bit_width 578 / 8; 579 if (sc->sc_pct_stat_as == 0) 580 sc->sc_pct_stat_as = 4; 581 sc->sc_pct_ctrl_as = sc->sc_pct.pct_ctrl.grd_gas.register_bit_width / 8; 582 if (sc->sc_pct_ctrl_as == 0) 583 sc->sc_pct_ctrl_as = 4; 584 sc->sc_pct_stat_len = sc->sc_pct.pct_status.grd_gas.access_size; 585 if (sc->sc_pct_stat_len == 0) 586 sc->sc_pct_stat_len = sc->sc_pct_stat_as; 587 sc->sc_pct_ctrl_len = sc->sc_pct.pct_ctrl.grd_gas.access_size; 588 if (sc->sc_pct_ctrl_len == 0) 589 sc->sc_pct_ctrl_len = sc->sc_pct_ctrl_as; 590 591 rv = 0; 592 ffh: 593 aml_freevalue(&res); 594 return (rv); 595 } 596 597 int 598 acpicpu_getpss(struct acpicpu_softc *sc) 599 { 600 struct aml_value res; 601 int i, c, cf; 602 603 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PSS", 0, NULL, &res)) { 604 dprintf("%s: no _PSS\n", DEVNAME(sc)); 605 return (1); 606 } 607 608 if (sc->sc_pss) 609 free(sc->sc_pss, M_DEVBUF, 0); 610 611 sc->sc_pss = malloc(res.length * sizeof *sc->sc_pss, M_DEVBUF, 612 M_WAITOK | M_ZERO); 613 614 c = 0; 615 for (i = 0; i < res.length; i++) { 616 cf = aml_val2int(res.v_package[i]->v_package[0]); 617 618 /* This heuristic comes from FreeBSDs 619 * dev/acpica/acpi_perf.c to weed out invalid PSS entries. 620 */ 621 if (cf == sc->sc_pss[c].pss_core_freq) { 622 printf("%s: struck PSS entry, core frequency equals " 623 " last\n", sc->sc_dev.dv_xname); 624 continue; 625 } 626 627 if (cf == 0xFFFF || cf == 0x9999 || cf == 99999 || cf == 0) { 628 printf("%s: struck PSS entry, inappropriate core " 629 "frequency value\n", sc->sc_dev.dv_xname); 630 continue; 631 } 632 633 sc->sc_pss[c].pss_core_freq = cf; 634 sc->sc_pss[c].pss_power = aml_val2int( 635 res.v_package[i]->v_package[1]); 636 sc->sc_pss[c].pss_trans_latency = aml_val2int( 637 res.v_package[i]->v_package[2]); 638 sc->sc_pss[c].pss_bus_latency = aml_val2int( 639 res.v_package[i]->v_package[3]); 640 sc->sc_pss[c].pss_ctrl = aml_val2int( 641 res.v_package[i]->v_package[4]); 642 sc->sc_pss[c].pss_status = aml_val2int( 643 res.v_package[i]->v_package[5]); 644 c++; 645 } 646 sc->sc_pss_len = c; 647 648 aml_freevalue(&res); 649 650 return (0); 651 } 652 653 int 654 acpicpu_fetch_pss(struct acpicpu_pss **pss) 655 { 656 struct acpicpu_softc *sc; 657 658 /* 659 * XXX: According to the ACPI spec in an SMP system all processors 660 * are supposed to support the same states. For now we pray 661 * the bios ensures this... 662 */ 663 664 sc = acpicpu_sc[0]; 665 if (!sc) 666 return 0; 667 *pss = sc->sc_pss; 668 669 return (sc->sc_pss_len); 670 } 671 672 int 673 acpicpu_notify(struct aml_node *node, int notify_type, void *arg) 674 { 675 struct acpicpu_softc *sc = arg; 676 677 dnprintf(10, "acpicpu_notify: %.2x %s\n", notify_type, 678 sc->sc_devnode->name); 679 680 switch (notify_type) { 681 case 0x80: /* _PPC changed, retrieve new values */ 682 acpicpu_getppc(sc); 683 acpicpu_getpss(sc); 684 if (sc->sc_notify) 685 sc->sc_notify(sc->sc_pss, sc->sc_pss_len); 686 687 break; 688 default: 689 printf("%s: unhandled cpu event %x\n", DEVNAME(sc), 690 notify_type); 691 break; 692 } 693 694 return (0); 695 } 696 697 void 698 acpicpu_set_notify(void (*func)(struct acpicpu_pss *, int)) 699 { 700 struct acpicpu_softc *sc; 701 702 sc = acpicpu_sc[0]; 703 if (sc != NULL) 704 sc->sc_notify = func; 705 } 706 707 void 708 acpicpu_setperf_ppc_change(struct acpicpu_pss *pss, int npss) 709 { 710 struct acpicpu_softc *sc; 711 712 sc = acpicpu_sc[0]; 713 714 if (sc != NULL) 715 cpu_setperf(sc->sc_level); 716 } 717 718 void 719 acpicpu_setperf(int level) 720 { 721 struct acpicpu_softc *sc; 722 struct acpicpu_pss *pss = NULL; 723 int idx, len; 724 u_int32_t status = 0; 725 726 sc = acpicpu_sc[cpu_number()]; 727 728 dnprintf(10, "%s: acpicpu setperf level %d\n", 729 sc->sc_devnode->name, level); 730 731 if (level < 0 || level > 100) { 732 dnprintf(10, "%s: acpicpu setperf illegal percentage\n", 733 sc->sc_devnode->name); 734 return; 735 } 736 737 /* 738 * XXX this should be handled more gracefully and it needs to also do 739 * the duty cycle method instead of pss exclusively 740 */ 741 if (sc->sc_flags & FLAGS_NOPSS || sc->sc_flags & FLAGS_NOPCT) { 742 dnprintf(10, "%s: acpicpu no _PSS or _PCT\n", 743 sc->sc_devnode->name); 744 return; 745 } 746 747 if (sc->sc_ppc) 748 len = sc->sc_ppc; 749 else 750 len = sc->sc_pss_len; 751 idx = (len - 1) - (level / (100 / len)); 752 if (idx < 0) 753 idx = 0; 754 755 if (sc->sc_ppc) 756 idx += sc->sc_pss_len - sc->sc_ppc; 757 758 if (idx > sc->sc_pss_len) 759 idx = sc->sc_pss_len - 1; 760 761 dnprintf(10, "%s: acpicpu setperf index %d pss_len %d ppc %d\n", 762 sc->sc_devnode->name, idx, sc->sc_pss_len, sc->sc_ppc); 763 764 pss = &sc->sc_pss[idx]; 765 766 #ifdef ACPI_DEBUG 767 /* keep this for now since we will need this for debug in the field */ 768 printf("0 status: %x %llx %u %u ctrl: %x %llx %u %u\n", 769 sc->sc_pct.pct_status.grd_gas.address_space_id, 770 sc->sc_pct.pct_status.grd_gas.address, 771 sc->sc_pct_stat_as, sc->sc_pct_stat_len, 772 sc->sc_pct.pct_ctrl.grd_gas.address_space_id, 773 sc->sc_pct.pct_ctrl.grd_gas.address, 774 sc->sc_pct_ctrl_as, sc->sc_pct_ctrl_len); 775 #endif 776 acpi_gasio(sc->sc_acpi, ACPI_IOREAD, 777 sc->sc_pct.pct_status.grd_gas.address_space_id, 778 sc->sc_pct.pct_status.grd_gas.address, sc->sc_pct_stat_as, 779 sc->sc_pct_stat_len, &status); 780 dnprintf(20, "1 status: %u <- %u\n", status, pss->pss_status); 781 782 /* Are we already at the requested frequency? */ 783 if (status == pss->pss_status) 784 return; 785 786 acpi_gasio(sc->sc_acpi, ACPI_IOWRITE, 787 sc->sc_pct.pct_ctrl.grd_gas.address_space_id, 788 sc->sc_pct.pct_ctrl.grd_gas.address, sc->sc_pct_ctrl_as, 789 sc->sc_pct_ctrl_len, &pss->pss_ctrl); 790 dnprintf(20, "pss_ctrl: %x\n", pss->pss_ctrl); 791 792 acpi_gasio(sc->sc_acpi, ACPI_IOREAD, 793 sc->sc_pct.pct_status.grd_gas.address_space_id, 794 sc->sc_pct.pct_status.grd_gas.address, sc->sc_pct_stat_as, 795 sc->sc_pct_stat_as, &status); 796 dnprintf(20, "2 status: %d\n", status); 797 798 /* Did the transition succeed? */ 799 if (status == pss->pss_status) { 800 cpuspeed = pss->pss_core_freq; 801 sc->sc_level = level; 802 } else 803 printf("%s: acpicpu setperf failed to alter frequency\n", 804 sc->sc_devnode->name); 805 } 806