1 /* $OpenBSD: acpicpu.c,v 1.57 2010/07/21 19:35:15 deraadt 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 buf[3]; 199 200 /* 4077A616-290C-47BE-9EBD-D87058713953 */ 201 static uint8_t cpu_oscuuid[16] = { 0x16, 0xA6, 0x77, 0x40, 0x0C, 0x29, 202 0xBE, 0x47, 0x9E, 0xBD, 0xD8, 0x70, 203 0x58, 0x71, 0x39, 0x53 }; 204 /* Evaluate _PDC */ 205 memset(&cmd, 0, sizeof(cmd)); 206 cmd.type = AML_OBJTYPE_BUFFER; 207 cmd.v_buffer = (uint8_t *)&buf; 208 cmd.length = sizeof(buf); 209 210 buf[0] = ACPI_PDC_REVID; 211 buf[1] = 1; 212 buf[2] = ACPI_PDC_C_C1_HALT | ACPI_PDC_P_FFH | ACPI_PDC_C_C1_FFH 213 | ACPI_PDC_C_C2C3_FFH | ACPI_PDC_SMP_P_SWCOORD | ACPI_PDC_SMP_C2C3 214 | ACPI_PDC_SMP_C1PT; 215 216 aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PDC", 1, &cmd, &res); 217 218 /* Evaluate _OSC */ 219 memset(&osc_cmd, 0, sizeof(cmd) * 4); 220 osc_cmd[0].type = AML_OBJTYPE_BUFFER; 221 osc_cmd[0].v_buffer = (uint8_t *)&cpu_oscuuid; 222 osc_cmd[0].length = sizeof(cpu_oscuuid); 223 224 osc_cmd[1].type = AML_OBJTYPE_INTEGER; 225 osc_cmd[1].v_integer = 1; 226 osc_cmd[1].length = 1; 227 228 osc_cmd[2].type = AML_OBJTYPE_INTEGER; 229 osc_cmd[2].v_integer = 1; 230 osc_cmd[2].length = 1; 231 232 buf[0] = 0; 233 osc_cmd[3].type = AML_OBJTYPE_BUFFER; 234 osc_cmd[3].v_buffer = (int8_t *)&buf; 235 osc_cmd[3].length = sizeof(buf); 236 237 aml_evalname(sc->sc_acpi, sc->sc_devnode, "_OSC", 4, osc_cmd, &res); 238 } 239 240 241 struct acpi_cstate * 242 acpicpu_add_cstate(struct acpicpu_softc *sc, int type, int latency, int power, 243 int address) 244 { 245 struct acpi_cstate *cx; 246 247 dnprintf(10," C%d: latency:.%4x power:%.4x addr:%.8x\n", 248 type, latency, power, address); 249 250 switch (type) { 251 case ACPI_STATE_C2: 252 if (latency > ACPI_MAX_C2_LATENCY || !address || 253 (sc->sc_flags & FLAGS_NO_C2)) 254 goto bad; 255 break; 256 case ACPI_STATE_C3: 257 if (latency > ACPI_MAX_C3_LATENCY || !address || 258 (sc->sc_flags & FLAGS_NO_C3)) 259 goto bad; 260 break; 261 } 262 263 cx = malloc(sizeof(*cx), M_DEVBUF, M_WAITOK | M_ZERO); 264 265 cx->type = type; 266 cx->power = power; 267 cx->latency = latency; 268 cx->address = address; 269 270 SLIST_INSERT_HEAD(&sc->sc_cstates, cx, link); 271 272 return (cx); 273 bad: 274 dprintf("acpicpu%d: C%d not supported", sc->sc_cpu, type); 275 return (NULL); 276 } 277 278 /* Found a _CST object, add new cstate for each entry */ 279 void 280 acpicpu_add_cstatepkg(struct aml_value *val, void *arg) 281 { 282 struct acpicpu_softc *sc = arg; 283 284 #if defined(ACPI_DEBUG) && !defined(SMALL_KERNEL) 285 aml_showvalue(val, 0); 286 #endif 287 if (val->type != AML_OBJTYPE_PACKAGE || val->length != 4) 288 return; 289 290 acpicpu_add_cstate(sc, val->v_package[1]->v_integer, 291 val->v_package[2]->v_integer, 292 val->v_package[3]->v_integer, -1); 293 } 294 295 296 int 297 acpicpu_match(struct device *parent, void *match, void *aux) 298 { 299 struct acpi_attach_args *aa = aux; 300 struct cfdata *cf = match; 301 302 /* sanity */ 303 if (aa->aaa_name == NULL || 304 strcmp(aa->aaa_name, cf->cf_driver->cd_name) != 0 || 305 aa->aaa_table != NULL) 306 return (0); 307 308 return (1); 309 } 310 311 void 312 acpicpu_attach(struct device *parent, struct device *self, void *aux) 313 { 314 struct acpicpu_softc *sc = (struct acpicpu_softc *)self; 315 struct acpi_attach_args *aa = aux; 316 struct aml_value res; 317 int i; 318 struct acpi_cstate *cx; 319 u_int32_t status = 0; 320 321 sc->sc_acpi = (struct acpi_softc *)parent; 322 sc->sc_devnode = aa->aaa_node; 323 acpicpu_sc[sc->sc_dev.dv_unit] = sc; 324 325 SLIST_INIT(&sc->sc_cstates); 326 327 sc->sc_pss = NULL; 328 329 if (aml_evalnode(sc->sc_acpi, sc->sc_devnode, 0, NULL, &res) == 0) { 330 if (res.type == AML_OBJTYPE_PROCESSOR) { 331 sc->sc_cpu = res.v_processor.proc_id; 332 sc->sc_pblk_addr = res.v_processor.proc_addr; 333 sc->sc_pblk_len = res.v_processor.proc_len; 334 } 335 aml_freevalue(&res); 336 } 337 sc->sc_duty_off = sc->sc_acpi->sc_fadt->duty_offset; 338 sc->sc_duty_wid = sc->sc_acpi->sc_fadt->duty_width; 339 340 acpicpu_set_pdc(sc); 341 342 if (!valid_throttle(sc->sc_duty_off, sc->sc_duty_wid, sc->sc_pblk_addr)) 343 sc->sc_flags |= FLAGS_NOTHROTTLE; 344 #ifdef ACPI_DEBUG 345 printf(": %s: ", sc->sc_devnode->name); 346 printf("\n: hdr:%x pblk:%x,%x duty:%x,%x pstate:%x " 347 "(%d throttling states)\n", sc->sc_acpi->sc_fadt->hdr_revision, 348 sc->sc_pblk_addr, sc->sc_pblk_len, sc->sc_duty_off, 349 sc->sc_duty_wid, sc->sc_acpi->sc_fadt->pstate_cnt, 350 CPU_MAXSTATE(sc)); 351 #endif 352 353 /* Get C-States from _CST or FADT */ 354 if (!aml_evalname(sc->sc_acpi, sc->sc_devnode, "_CST", 0, NULL, &res)) { 355 aml_foreachpkg(&res, 1, acpicpu_add_cstatepkg, sc); 356 aml_freevalue(&res); 357 } 358 else { 359 /* Some systems don't export a full PBLK reduce functionality */ 360 if (sc->sc_pblk_len < 5) 361 sc->sc_flags |= FLAGS_NO_C2; 362 if (sc->sc_pblk_len < 6) 363 sc->sc_flags |= FLAGS_NO_C3; 364 acpicpu_add_cstate(sc, ACPI_STATE_C2, 365 sc->sc_acpi->sc_fadt->p_lvl2_lat, -1, 366 sc->sc_pblk_addr + 4); 367 acpicpu_add_cstate(sc, ACPI_STATE_C3, 368 sc->sc_acpi->sc_fadt->p_lvl3_lat, -1, 369 sc->sc_pblk_addr + 5); 370 } 371 if (acpicpu_getpss(sc)) { 372 sc->sc_flags |= FLAGS_NOPSS; 373 } else { 374 #ifdef ACPI_DEBUG 375 for (i = 0; i < sc->sc_pss_len; i++) { 376 dnprintf(20, "%d %d %d %d %d %d\n", 377 sc->sc_pss[i].pss_core_freq, 378 sc->sc_pss[i].pss_power, 379 sc->sc_pss[i].pss_trans_latency, 380 sc->sc_pss[i].pss_bus_latency, 381 sc->sc_pss[i].pss_ctrl, 382 sc->sc_pss[i].pss_status); 383 } 384 dnprintf(20, "\n"); 385 #endif 386 if (sc->sc_pss_len == 0) { 387 /* this should never happen */ 388 printf("%s: invalid _PSS length\n", DEVNAME(sc)); 389 sc->sc_flags |= FLAGS_NOPSS; 390 } 391 392 acpicpu_getppc(sc); 393 if (acpicpu_getpct(sc)) 394 sc->sc_flags |= FLAGS_NOPCT; 395 else if (sc->sc_pss_len > 0) { 396 /* Notify BIOS we are handing p-states */ 397 if (sc->sc_acpi->sc_fadt->pstate_cnt) 398 acpi_write_pmreg(sc->sc_acpi, ACPIREG_SMICMD, 0, 399 sc->sc_acpi->sc_fadt->pstate_cnt); 400 401 aml_register_notify(sc->sc_devnode, NULL, 402 acpicpu_notify, sc, ACPIDEV_NOPOLL); 403 404 acpi_gasio(sc->sc_acpi, ACPI_IOREAD, 405 sc->sc_pct.pct_status.grd_gas.address_space_id, 406 sc->sc_pct.pct_status.grd_gas.address, 407 sc->sc_pct_stat_as, sc->sc_pct_stat_as, &status); 408 sc->sc_level = (100 / sc->sc_pss_len) * 409 (sc->sc_pss_len - status); 410 dnprintf(20, "%s: cpu index %d, percentage %d\n", 411 DEVNAME(sc), status, sc->sc_level); 412 if (setperf_prio < 30) { 413 cpu_setperf = acpicpu_setperf; 414 acpicpu_set_notify(acpicpu_setperf_ppc_change); 415 setperf_prio = 30; 416 acpi_hasprocfvs = 1; 417 } 418 } 419 } 420 421 /* 422 * Nicely enumerate what power management capabilities 423 * ACPI CPU provides. 424 */ 425 if (!SLIST_EMPTY(&sc->sc_cstates)) { 426 printf(":"); 427 428 i = 0; 429 SLIST_FOREACH(cx, &sc->sc_cstates, link) { 430 if (i++) 431 printf(","); 432 switch (cx->type) { 433 case ACPI_STATE_C0: 434 printf(" C0"); 435 break; 436 case ACPI_STATE_C1: 437 printf(" C1"); 438 break; 439 case ACPI_STATE_C2: 440 printf(" C2"); 441 break; 442 case ACPI_STATE_C3: 443 printf(" C3"); 444 break; 445 } 446 } 447 } 448 449 if (!(sc->sc_flags & (FLAGS_NOPSS | FLAGS_NOPCT)) || 450 !(sc->sc_flags & FLAGS_NOPSS)) { 451 printf("%c ", SLIST_EMPTY(&sc->sc_cstates) ? ':' : ','); 452 453 /* 454 * If acpicpu is itself providing the capability to transition 455 * states, enumerate them in the fashion that est and powernow 456 * would. 457 */ 458 if (!(sc->sc_flags & (FLAGS_NOPSS | FLAGS_NOPCT))) { 459 printf("FVS, "); 460 for (i = 0; i < sc->sc_pss_len - 1; i++) 461 printf("%d, ", sc->sc_pss[i].pss_core_freq); 462 printf("%d MHz", sc->sc_pss[i].pss_core_freq); 463 } else 464 printf("PSS"); 465 } 466 467 printf("\n"); 468 } 469 470 int 471 acpicpu_getppc(struct acpicpu_softc *sc) 472 { 473 struct aml_value res; 474 475 sc->sc_ppc = 0; 476 477 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PPC", 0, NULL, &res)) { 478 dnprintf(10, "%s: no _PPC\n", DEVNAME(sc)); 479 return (1); 480 } 481 482 sc->sc_ppc = aml_val2int(&res); 483 dnprintf(10, "%s: _PPC: %d\n", DEVNAME(sc), sc->sc_ppc); 484 aml_freevalue(&res); 485 486 return (0); 487 } 488 489 int 490 acpicpu_getpct(struct acpicpu_softc *sc) 491 { 492 struct aml_value res; 493 int rv = 1; 494 495 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PCT", 0, NULL, &res)) { 496 dnprintf(20, "%s: no _PCT\n", DEVNAME(sc)); 497 return (1); 498 } 499 500 if (res.length != 2) { 501 dnprintf(20, "%s: %s: invalid _PCT length\n", DEVNAME(sc), 502 sc->sc_devnode->name); 503 return (1); 504 } 505 506 memcpy(&sc->sc_pct.pct_ctrl, res.v_package[0]->v_buffer, 507 sizeof sc->sc_pct.pct_ctrl); 508 if (sc->sc_pct.pct_ctrl.grd_gas.address_space_id == 509 GAS_FUNCTIONAL_FIXED) { 510 dnprintf(20, "CTRL GASIO is functional fixed hardware.\n"); 511 goto ffh; 512 } 513 514 memcpy(&sc->sc_pct.pct_status, res.v_package[1]->v_buffer, 515 sizeof sc->sc_pct.pct_status); 516 if (sc->sc_pct.pct_status.grd_gas.address_space_id == 517 GAS_FUNCTIONAL_FIXED) { 518 dnprintf(20, "CTRL GASIO is functional fixed hardware.\n"); 519 goto ffh; 520 } 521 522 dnprintf(10, "_PCT(ctrl) : %02x %04x %02x %02x %02x %02x %016x\n", 523 sc->sc_pct.pct_ctrl.grd_descriptor, 524 sc->sc_pct.pct_ctrl.grd_length, 525 sc->sc_pct.pct_ctrl.grd_gas.address_space_id, 526 sc->sc_pct.pct_ctrl.grd_gas.register_bit_width, 527 sc->sc_pct.pct_ctrl.grd_gas.register_bit_offset, 528 sc->sc_pct.pct_ctrl.grd_gas.access_size, 529 sc->sc_pct.pct_ctrl.grd_gas.address); 530 531 dnprintf(10, "_PCT(status): %02x %04x %02x %02x %02x %02x %016x\n", 532 sc->sc_pct.pct_status.grd_descriptor, 533 sc->sc_pct.pct_status.grd_length, 534 sc->sc_pct.pct_status.grd_gas.address_space_id, 535 sc->sc_pct.pct_status.grd_gas.register_bit_width, 536 sc->sc_pct.pct_status.grd_gas.register_bit_offset, 537 sc->sc_pct.pct_status.grd_gas.access_size, 538 sc->sc_pct.pct_status.grd_gas.address); 539 540 /* if not set assume single 32 bit access */ 541 sc->sc_pct_stat_as = sc->sc_pct.pct_status.grd_gas.register_bit_width 542 / 8; 543 if (sc->sc_pct_stat_as == 0) 544 sc->sc_pct_stat_as = 4; 545 sc->sc_pct_ctrl_as = sc->sc_pct.pct_ctrl.grd_gas.register_bit_width / 8; 546 if (sc->sc_pct_ctrl_as == 0) 547 sc->sc_pct_ctrl_as = 4; 548 sc->sc_pct_stat_len = sc->sc_pct.pct_status.grd_gas.access_size; 549 if (sc->sc_pct_stat_len == 0) 550 sc->sc_pct_stat_len = sc->sc_pct_stat_as; 551 sc->sc_pct_ctrl_len = sc->sc_pct.pct_ctrl.grd_gas.access_size; 552 if (sc->sc_pct_ctrl_len == 0) 553 sc->sc_pct_ctrl_len = sc->sc_pct_ctrl_as; 554 555 rv = 0; 556 ffh: 557 aml_freevalue(&res); 558 return (rv); 559 } 560 561 int 562 acpicpu_getpss(struct acpicpu_softc *sc) 563 { 564 struct aml_value res; 565 int i, c, cf; 566 567 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PSS", 0, NULL, &res)) { 568 dprintf("%s: no _PSS\n", DEVNAME(sc)); 569 return (1); 570 } 571 572 if (sc->sc_pss) 573 free(sc->sc_pss, M_DEVBUF); 574 575 sc->sc_pss = malloc(res.length * sizeof *sc->sc_pss, M_DEVBUF, 576 M_WAITOK | M_ZERO); 577 578 c = 0; 579 for (i = 0; i < res.length; i++) { 580 cf = aml_val2int(res.v_package[i]->v_package[0]); 581 582 /* This heuristic comes from FreeBSDs 583 * dev/acpica/acpi_perf.c to weed out invalid PSS entries. 584 */ 585 if (cf == sc->sc_pss[c].pss_core_freq) { 586 printf("%s: struck PSS entry, core frequency equals " 587 " last\n", sc->sc_dev.dv_xname); 588 continue; 589 } 590 591 if (cf == 0xFFFF || cf == 0x9999 || cf == 99999 || cf == 0) { 592 printf("%s: struck PSS entry, inappropriate core " 593 "frequency value\n", sc->sc_dev.dv_xname); 594 continue; 595 } 596 597 sc->sc_pss[c].pss_core_freq = cf; 598 sc->sc_pss[c].pss_power = aml_val2int( 599 res.v_package[i]->v_package[1]); 600 sc->sc_pss[c].pss_trans_latency = aml_val2int( 601 res.v_package[i]->v_package[2]); 602 sc->sc_pss[c].pss_bus_latency = aml_val2int( 603 res.v_package[i]->v_package[3]); 604 sc->sc_pss[c].pss_ctrl = aml_val2int( 605 res.v_package[i]->v_package[4]); 606 sc->sc_pss[c].pss_status = aml_val2int( 607 res.v_package[i]->v_package[5]); 608 c++; 609 } 610 sc->sc_pss_len = c; 611 612 aml_freevalue(&res); 613 614 return (0); 615 } 616 617 int 618 acpicpu_fetch_pss(struct acpicpu_pss **pss) 619 { 620 struct acpicpu_softc *sc; 621 622 /* 623 * XXX: According to the ACPI spec in an SMP system all processors 624 * are supposed to support the same states. For now we pray 625 * the bios ensures this... 626 */ 627 628 sc = acpicpu_sc[0]; 629 if (!sc) 630 return 0; 631 *pss = sc->sc_pss; 632 633 return (sc->sc_pss_len); 634 } 635 636 int 637 acpicpu_notify(struct aml_node *node, int notify_type, void *arg) 638 { 639 struct acpicpu_softc *sc = arg; 640 641 dnprintf(10, "acpicpu_notify: %.2x %s\n", notify_type, 642 sc->sc_devnode->name); 643 644 switch (notify_type) { 645 case 0x80: /* _PPC changed, retrieve new values */ 646 acpicpu_getppc(sc); 647 acpicpu_getpss(sc); 648 if (sc->sc_notify) 649 sc->sc_notify(sc->sc_pss, sc->sc_pss_len); 650 651 break; 652 default: 653 printf("%s: unhandled cpu event %x\n", DEVNAME(sc), 654 notify_type); 655 break; 656 } 657 658 return (0); 659 } 660 661 void 662 acpicpu_set_notify(void (*func)(struct acpicpu_pss *, int)) 663 { 664 struct acpicpu_softc *sc; 665 666 sc = acpicpu_sc[0]; 667 if (sc != NULL) 668 sc->sc_notify = func; 669 } 670 671 void 672 acpicpu_setperf_ppc_change(struct acpicpu_pss *pss, int npss) 673 { 674 struct acpicpu_softc *sc; 675 676 sc = acpicpu_sc[0]; 677 678 if (sc != NULL) 679 cpu_setperf(sc->sc_level); 680 } 681 682 void 683 acpicpu_setperf(int level) 684 { 685 struct acpicpu_softc *sc; 686 struct acpicpu_pss *pss = NULL; 687 int idx, len; 688 u_int32_t status = 0; 689 690 sc = acpicpu_sc[cpu_number()]; 691 692 dnprintf(10, "%s: acpicpu setperf level %d\n", 693 sc->sc_devnode->name, level); 694 695 if (level < 0 || level > 100) { 696 dnprintf(10, "%s: acpicpu setperf illegal percentage\n", 697 sc->sc_devnode->name); 698 return; 699 } 700 701 /* 702 * XXX this should be handled more gracefully and it needs to also do 703 * the duty cycle method instead of pss exclusively 704 */ 705 if (sc->sc_flags & FLAGS_NOPSS || sc->sc_flags & FLAGS_NOPCT) { 706 dnprintf(10, "%s: acpicpu no _PSS or _PCT\n", 707 sc->sc_devnode->name); 708 return; 709 } 710 711 if (sc->sc_ppc) 712 len = sc->sc_ppc; 713 else 714 len = sc->sc_pss_len; 715 idx = (len - 1) - (level / (100 / len)); 716 if (idx < 0) 717 idx = 0; 718 719 if (sc->sc_ppc) 720 idx += sc->sc_pss_len - sc->sc_ppc; 721 722 if (idx > sc->sc_pss_len) 723 idx = sc->sc_pss_len - 1; 724 725 dnprintf(10, "%s: acpicpu setperf index %d pss_len %d ppc %d\n", 726 sc->sc_devnode->name, idx, sc->sc_pss_len, sc->sc_ppc); 727 728 pss = &sc->sc_pss[idx]; 729 730 #ifdef ACPI_DEBUG 731 /* keep this for now since we will need this for debug in the field */ 732 printf("0 status: %x %llx %u %u ctrl: %x %llx %u %u\n", 733 sc->sc_pct.pct_status.grd_gas.address_space_id, 734 sc->sc_pct.pct_status.grd_gas.address, 735 sc->sc_pct_stat_as, sc->sc_pct_stat_len, 736 sc->sc_pct.pct_ctrl.grd_gas.address_space_id, 737 sc->sc_pct.pct_ctrl.grd_gas.address, 738 sc->sc_pct_ctrl_as, sc->sc_pct_ctrl_len); 739 #endif 740 acpi_gasio(sc->sc_acpi, ACPI_IOREAD, 741 sc->sc_pct.pct_status.grd_gas.address_space_id, 742 sc->sc_pct.pct_status.grd_gas.address, sc->sc_pct_stat_as, 743 sc->sc_pct_stat_len, &status); 744 dnprintf(20, "1 status: %u <- %u\n", status, pss->pss_status); 745 746 /* Are we already at the requested frequency? */ 747 if (status == pss->pss_status) 748 return; 749 750 acpi_gasio(sc->sc_acpi, ACPI_IOWRITE, 751 sc->sc_pct.pct_ctrl.grd_gas.address_space_id, 752 sc->sc_pct.pct_ctrl.grd_gas.address, sc->sc_pct_ctrl_as, 753 sc->sc_pct_ctrl_len, &pss->pss_ctrl); 754 dnprintf(20, "pss_ctrl: %x\n", pss->pss_ctrl); 755 756 acpi_gasio(sc->sc_acpi, ACPI_IOREAD, 757 sc->sc_pct.pct_status.grd_gas.address_space_id, 758 sc->sc_pct.pct_status.grd_gas.address, sc->sc_pct_stat_as, 759 sc->sc_pct_stat_as, &status); 760 dnprintf(20, "2 status: %d\n", status); 761 762 /* Did the transition succeed? */ 763 if (status == pss->pss_status) { 764 cpuspeed = pss->pss_core_freq; 765 sc->sc_level = level; 766 } else 767 printf("%s: acpicpu setperf failed to alter frequency\n", 768 sc->sc_devnode->name); 769 } 770