Annotation of sys/dev/acpi/acpicpu.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: acpicpu.c,v 1.26 2007/06/15 22:37:40 gwk 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:
! 45: #define ACPI_STATE_C0 0x00
! 46: #define ACPI_STATE_C1 0x01
! 47: #define ACPI_STATE_C2 0x02
! 48: #define ACPI_STATE_C3 0x03
! 49:
! 50: #define FLAGS_NO_C2 0x01
! 51: #define FLAGS_NO_C3 0x02
! 52: #define FLAGS_BMCHECK 0x04
! 53: #define FLAGS_NOTHROTTLE 0x08
! 54: #define FLAGS_NOPSS 0x10
! 55: #define FLAGS_NOPCT 0x20
! 56:
! 57: #define CPU_THT_EN (1L << 4)
! 58: #define CPU_MAXSTATE(sc) (1L << (sc)->sc_duty_wid)
! 59: #define CPU_STATE(sc,pct) ((pct * CPU_MAXSTATE(sc) / 100) << (sc)->sc_duty_off)
! 60: #define CPU_STATEMASK(sc) ((CPU_MAXSTATE(sc) - 1) << (sc)->sc_duty_off)
! 61:
! 62: #define ACPI_MAX_C2_LATENCY 100
! 63: #define ACPI_MAX_C3_LATENCY 1000
! 64:
! 65: /* Make sure throttling bits are valid,a=addr,o=offset,w=width */
! 66: #define valid_throttle(o,w,a) (a && w && (o+w)<=31 && (o>4 || (o+w)<=4))
! 67:
! 68: struct acpi_cstate
! 69: {
! 70: int type;
! 71: int latency;
! 72: int power;
! 73: int address;
! 74:
! 75: SLIST_ENTRY(acpi_cstate) link;
! 76: };
! 77:
! 78: struct acpicpu_softc {
! 79: struct device sc_dev;
! 80: int sc_cpu;
! 81:
! 82: int sc_duty_wid;
! 83: int sc_duty_off;
! 84: int sc_pblk_addr;
! 85: int sc_pblk_len;
! 86: int sc_flags;
! 87:
! 88: SLIST_HEAD(,acpi_cstate) sc_cstates;
! 89:
! 90: bus_space_tag_t sc_iot;
! 91: bus_space_handle_t sc_ioh;
! 92:
! 93: struct acpi_softc *sc_acpi;
! 94: struct aml_node *sc_devnode;
! 95:
! 96: int sc_pss_len;
! 97: struct acpicpu_pss *sc_pss;
! 98:
! 99: struct acpicpu_pct sc_pct;
! 100: /* XXX: _PPC Change listener
! 101: * PPC changes can occur when for example a machine is disconnected
! 102: * from AC power and can no loger support the highest frequency or
! 103: * voltage when driven from the battery.
! 104: * Should probably be reimplemented as a list for now we assume only
! 105: * one listener */
! 106: void (*sc_notify)(struct acpicpu_pss *, int);
! 107: };
! 108:
! 109: void acpicpu_set_throttle(struct acpicpu_softc *, int);
! 110: void acpicpu_add_cstatepkg(struct aml_value *, void *);
! 111: int acpicpu_getpct(struct acpicpu_softc *);
! 112: int acpicpu_getpss(struct acpicpu_softc *);
! 113: struct acpi_cstate *acpicpu_add_cstate(struct acpicpu_softc *, int, int, int, int);
! 114: struct acpi_cstate *acpicpu_find_cstate(struct acpicpu_softc *, int);
! 115:
! 116: struct cfattach acpicpu_ca = {
! 117: sizeof(struct acpicpu_softc), acpicpu_match, acpicpu_attach
! 118: };
! 119:
! 120: struct cfdriver acpicpu_cd = {
! 121: NULL, "acpicpu", DV_DULL
! 122: };
! 123:
! 124: extern int setperf_prio;
! 125:
! 126: #ifdef __i386__
! 127: struct acpicpu_softc *acpicpu_sc[I386_MAXPROCS];
! 128: #elif __amd64__
! 129: struct acpicpu_softc *acpicpu_sc[X86_MAXPROCS];
! 130: #endif
! 131:
! 132: void
! 133: acpicpu_set_throttle(struct acpicpu_softc *sc, int level)
! 134: {
! 135: uint32_t pbval;
! 136:
! 137: if (sc->sc_flags & FLAGS_NOTHROTTLE)
! 138: return;
! 139:
! 140: /* Disable throttling control */
! 141: pbval = inl(sc->sc_pblk_addr);
! 142: outl(sc->sc_pblk_addr, pbval & ~CPU_THT_EN);
! 143: if (level < 100) {
! 144: pbval &= ~CPU_STATEMASK(sc);
! 145: pbval |= CPU_STATE(sc, level);
! 146: outl(sc->sc_pblk_addr, pbval & ~CPU_THT_EN);
! 147: outl(sc->sc_pblk_addr, pbval | CPU_THT_EN);
! 148: }
! 149: }
! 150:
! 151: struct acpi_cstate *
! 152: acpicpu_find_cstate(struct acpicpu_softc *sc, int type)
! 153: {
! 154: struct acpi_cstate *cx;
! 155:
! 156: SLIST_FOREACH(cx, &sc->sc_cstates, link)
! 157: if (cx->type == type)
! 158: return cx;
! 159: return NULL;
! 160: }
! 161:
! 162: struct acpi_cstate *
! 163: acpicpu_add_cstate(struct acpicpu_softc *sc, int type,
! 164: int latency, int power, int address)
! 165: {
! 166: struct acpi_cstate *cx;
! 167:
! 168: dnprintf(10," C%d: latency:.%4x power:%.4x addr:%.8x\n",
! 169: type, latency, power, address);
! 170:
! 171: switch (type) {
! 172: case ACPI_STATE_C2:
! 173: if (latency > ACPI_MAX_C2_LATENCY || !address ||
! 174: (sc->sc_flags & FLAGS_NO_C2))
! 175: goto bad;
! 176: break;
! 177: case ACPI_STATE_C3:
! 178: if (latency > ACPI_MAX_C3_LATENCY || !address ||
! 179: (sc->sc_flags & FLAGS_NO_C3))
! 180: goto bad;
! 181: break;
! 182: }
! 183:
! 184: cx = malloc(sizeof(struct acpi_cstate), M_DEVBUF, M_WAITOK);
! 185: memset(cx, 0, sizeof(struct acpi_cstate));
! 186:
! 187: cx->type = type;
! 188: cx->power = power;
! 189: cx->latency = latency;
! 190: cx->address = address;
! 191:
! 192: SLIST_INSERT_HEAD(&sc->sc_cstates, cx, link);
! 193:
! 194: return cx;
! 195: bad:
! 196: dprintf("acpicpu%d: C%d not supported", sc->sc_cpu, type);
! 197: return NULL;
! 198: }
! 199:
! 200: /* Found a _CST object, add new cstate for each entry */
! 201: void
! 202: acpicpu_add_cstatepkg(struct aml_value *val, void *arg)
! 203: {
! 204: struct acpicpu_softc *sc = arg;
! 205:
! 206: #ifdef ACPI_DEBUG
! 207: aml_showvalue(val, 0);
! 208: #endif
! 209: if (val->type != AML_OBJTYPE_PACKAGE || val->length != 4)
! 210: return;
! 211: acpicpu_add_cstate(sc, val->v_package[1]->v_integer,
! 212: val->v_package[2]->v_integer,
! 213: val->v_package[3]->v_integer,
! 214: -1);
! 215: }
! 216:
! 217:
! 218: int
! 219: acpicpu_match(struct device *parent, void *match, void *aux)
! 220: {
! 221: struct acpi_attach_args *aa = aux;
! 222: struct cfdata *cf = match;
! 223:
! 224: /* sanity */
! 225: if (aa->aaa_name == NULL ||
! 226: strcmp(aa->aaa_name, cf->cf_driver->cd_name) != 0 ||
! 227: aa->aaa_table != NULL)
! 228: return (0);
! 229:
! 230: return (1);
! 231: }
! 232:
! 233: void
! 234: acpicpu_attach(struct device *parent, struct device *self, void *aux)
! 235: {
! 236: struct acpicpu_softc *sc = (struct acpicpu_softc *)self;
! 237: struct acpi_attach_args *aa = aux;
! 238: struct aml_value res;
! 239: int i;
! 240: struct acpi_cstate *cx;
! 241:
! 242: sc->sc_acpi = (struct acpi_softc *)parent;
! 243: sc->sc_devnode = aa->aaa_node;
! 244: acpicpu_sc[sc->sc_dev.dv_unit] = sc;
! 245:
! 246: SLIST_INIT(&sc->sc_cstates);
! 247:
! 248: sc->sc_pss = NULL;
! 249:
! 250: if (aml_evalnode(sc->sc_acpi, sc->sc_devnode, 0, NULL, &res) == 0) {
! 251: if (res.type == AML_OBJTYPE_PROCESSOR) {
! 252: sc->sc_cpu = res.v_processor.proc_id;
! 253: sc->sc_pblk_addr = res.v_processor.proc_addr;
! 254: sc->sc_pblk_len = res.v_processor.proc_len;
! 255: }
! 256: aml_freevalue(&res);
! 257: }
! 258: sc->sc_duty_off = sc->sc_acpi->sc_fadt->duty_offset;
! 259: sc->sc_duty_wid = sc->sc_acpi->sc_fadt->duty_width;
! 260: if (!valid_throttle(sc->sc_duty_off, sc->sc_duty_wid, sc->sc_pblk_addr))
! 261: sc->sc_flags |= FLAGS_NOTHROTTLE;
! 262:
! 263: #ifdef ACPI_DEBUG
! 264: printf(": %s: ", sc->sc_devnode->name);
! 265: printf("\n: hdr:%x pblk:%x,%x duty:%x,%x pstate:%x (%d throttling states)\n",
! 266: sc->sc_acpi->sc_fadt->hdr_revision,
! 267: sc->sc_pblk_addr, sc->sc_pblk_len,
! 268: sc->sc_duty_off, sc->sc_duty_wid,
! 269: sc->sc_acpi->sc_fadt->pstate_cnt,
! 270: CPU_MAXSTATE(sc));
! 271: #endif
! 272:
! 273: /* Get C-States from _CST or FADT */
! 274: if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_CST", 0, NULL, &res) == 0) {
! 275: aml_foreachpkg(&res, 1, acpicpu_add_cstatepkg, sc);
! 276: aml_freevalue(&res);
! 277: }
! 278: else {
! 279: /* Some systems don't export a full PBLK, reduce functionality */
! 280: if (sc->sc_pblk_len < 5)
! 281: sc->sc_flags |= FLAGS_NO_C2;
! 282: if (sc->sc_pblk_len < 6)
! 283: sc->sc_flags |= FLAGS_NO_C3;
! 284: acpicpu_add_cstate(sc, ACPI_STATE_C2,
! 285: sc->sc_acpi->sc_fadt->p_lvl2_lat, -1,
! 286: sc->sc_pblk_addr + 4);
! 287: acpicpu_add_cstate(sc, ACPI_STATE_C3,
! 288: sc->sc_acpi->sc_fadt->p_lvl3_lat, -1,
! 289: sc->sc_pblk_addr + 5);
! 290: }
! 291: if (acpicpu_getpss(sc)) {
! 292: /* XXX not the right test but has to do for now */
! 293: sc->sc_flags |= FLAGS_NOPSS;
! 294: } else {
! 295:
! 296: #ifdef ACPI_DEBUG
! 297: for (i = 0; i < sc->sc_pss_len; i++) {
! 298: dnprintf(20, "%d %d %d %d %d %d\n",
! 299: sc->sc_pss[i].pss_core_freq,
! 300: sc->sc_pss[i].pss_power,
! 301: sc->sc_pss[i].pss_trans_latency,
! 302: sc->sc_pss[i].pss_bus_latency,
! 303: sc->sc_pss[i].pss_ctrl,
! 304: sc->sc_pss[i].pss_status);
! 305: }
! 306: dnprintf(20, "\n");
! 307: #endif
! 308: /* XXX this needs to be moved to probe routine */
! 309: if (acpicpu_getpct(sc))
! 310: sc->sc_flags |= FLAGS_NOPCT;
! 311: else {
! 312:
! 313: /* Notify BIOS we are handing p-states */
! 314: if (sc->sc_acpi->sc_fadt->pstate_cnt)
! 315: acpi_write_pmreg(sc->sc_acpi, ACPIREG_SMICMD, 0,
! 316: sc->sc_acpi->sc_fadt->pstate_cnt);
! 317:
! 318: aml_register_notify(sc->sc_devnode, NULL,
! 319: acpicpu_notify, sc, ACPIDEV_NOPOLL);
! 320:
! 321: if (setperf_prio < 30) {
! 322: cpu_setperf = acpicpu_setperf;
! 323: setperf_prio = 30;
! 324: acpi_hasprocfvs = 1;
! 325: }
! 326: }
! 327: }
! 328:
! 329: /*
! 330: * Nicely enumerate what power management capabilities
! 331: * ACPI CPU provides.
! 332: * */
! 333: i = 0;
! 334: SLIST_FOREACH(cx, &sc->sc_cstates, link) {
! 335: if (i)
! 336: printf(",");
! 337: switch(cx->type) {
! 338: case ACPI_STATE_C0:
! 339: printf(" C0");
! 340: break;
! 341: case ACPI_STATE_C1:
! 342: printf(" C1");
! 343: break;
! 344: case ACPI_STATE_C2:
! 345: printf(" C2");
! 346: break;
! 347: case ACPI_STATE_C3:
! 348: printf(" C3");
! 349: break;
! 350: }
! 351: i++;
! 352: }
! 353: if (!(sc->sc_flags & FLAGS_NOPSS) && !(sc->sc_flags & FLAGS_NOPCT)) {
! 354: if (i)
! 355: printf(",");
! 356: printf(" FVS");
! 357: } else if (!(sc->sc_flags & FLAGS_NOPSS)) {
! 358: if (i)
! 359: printf(",");
! 360: printf(" PSS");
! 361: }
! 362: printf("\n");
! 363:
! 364: /*
! 365: * If acpicpu is itself providing the capability to transition
! 366: * states, enumerate them in the fashion that est and powernow
! 367: * would.
! 368: */
! 369: if (!(sc->sc_flags & FLAGS_NOPSS) && !(sc->sc_flags & FLAGS_NOPCT)) {
! 370: printf("%s: ", sc->sc_dev.dv_xname);
! 371: for (i = 0; i < sc->sc_pss_len; i++)
! 372: printf("%d%s", sc->sc_pss[i].pss_core_freq,
! 373: i < sc->sc_pss_len - 1 ? ", " : " MHz\n");
! 374: }
! 375: }
! 376:
! 377: int
! 378: acpicpu_getpct(struct acpicpu_softc *sc)
! 379: {
! 380: struct aml_value res;
! 381: int rv = 1;
! 382:
! 383: if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PPC", 0, NULL, &res)) {
! 384: dnprintf(20, "%s: no _PPC\n", DEVNAME(sc));
! 385: dnprintf(10, "%s: no _PPC\n", DEVNAME(sc));
! 386: return (1);
! 387: }
! 388:
! 389: dnprintf(10, "_PPC: %d\n", aml_val2int(&res));
! 390: aml_freevalue(&res);
! 391:
! 392: if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PCT", 0, NULL, &res)) {
! 393: dnprintf(20, "%s: no _PCT\n", DEVNAME(sc));
! 394: return (1);
! 395: }
! 396:
! 397: if (res.length != 2) {
! 398: dnprintf(20, "%s: %s: invalid _PCT length\n", DEVNAME(sc),
! 399: sc->sc_devnode->name);
! 400: return (1);
! 401: }
! 402:
! 403: memcpy(&sc->sc_pct.pct_ctrl, res.v_package[0]->v_buffer,
! 404: sizeof sc->sc_pct.pct_ctrl);
! 405: if (sc->sc_pct.pct_ctrl.grd_gas.address_space_id ==
! 406: GAS_FUNCTIONAL_FIXED) {
! 407: dnprintf(20, "CTRL GASIO is functional fixed hardware.\n");
! 408: goto ffh;
! 409: }
! 410:
! 411: memcpy(&sc->sc_pct.pct_status, res.v_package[1]->v_buffer,
! 412: sizeof sc->sc_pct.pct_status);
! 413: if (sc->sc_pct.pct_status.grd_gas.address_space_id ==
! 414: GAS_FUNCTIONAL_FIXED) {
! 415: dnprintf(20, "CTRL GASIO is functional fixed hardware.\n");
! 416: goto ffh;
! 417: }
! 418:
! 419: dnprintf(10, "_PCT(ctrl) : %02x %04x %02x %02x %02x %02x %016x\n",
! 420: sc->sc_pct.pct_ctrl.grd_descriptor,
! 421: sc->sc_pct.pct_ctrl.grd_length,
! 422: sc->sc_pct.pct_ctrl.grd_gas.address_space_id,
! 423: sc->sc_pct.pct_ctrl.grd_gas.register_bit_width,
! 424: sc->sc_pct.pct_ctrl.grd_gas.register_bit_offset,
! 425: sc->sc_pct.pct_ctrl.grd_gas.access_size,
! 426: sc->sc_pct.pct_ctrl.grd_gas.address);
! 427:
! 428: dnprintf(10, "_PCT(status): %02x %04x %02x %02x %02x %02x %016x\n",
! 429: sc->sc_pct.pct_status.grd_descriptor,
! 430: sc->sc_pct.pct_status.grd_length,
! 431: sc->sc_pct.pct_status.grd_gas.address_space_id,
! 432: sc->sc_pct.pct_status.grd_gas.register_bit_width,
! 433: sc->sc_pct.pct_status.grd_gas.register_bit_offset,
! 434: sc->sc_pct.pct_status.grd_gas.access_size,
! 435: sc->sc_pct.pct_status.grd_gas.address);
! 436:
! 437: rv = 0;
! 438: ffh:
! 439: aml_freevalue(&res);
! 440: return (rv);
! 441: }
! 442:
! 443: int
! 444: acpicpu_getpss(struct acpicpu_softc *sc)
! 445: {
! 446: struct aml_value res;
! 447: int i;
! 448:
! 449: if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PSS", 0, NULL, &res)) {
! 450: dprintf("%s: no _PSS\n", DEVNAME(sc));
! 451: return (1);
! 452: }
! 453:
! 454: if (sc->sc_pss)
! 455: free(sc->sc_pss, M_DEVBUF);
! 456:
! 457: sc->sc_pss = malloc(res.length * sizeof *sc->sc_pss, M_DEVBUF,
! 458: M_WAITOK);
! 459:
! 460: memset(sc->sc_pss, 0, res.length * sizeof *sc->sc_pss);
! 461:
! 462: for (i = 0; i < res.length; i++) {
! 463: sc->sc_pss[i].pss_core_freq = aml_val2int(
! 464: res.v_package[i]->v_package[0]);
! 465: sc->sc_pss[i].pss_power = aml_val2int(
! 466: res.v_package[i]->v_package[1]);
! 467: sc->sc_pss[i].pss_trans_latency = aml_val2int(
! 468: res.v_package[i]->v_package[2]);
! 469: sc->sc_pss[i].pss_bus_latency = aml_val2int(
! 470: res.v_package[i]->v_package[3]);
! 471: sc->sc_pss[i].pss_ctrl = aml_val2int(
! 472: res.v_package[i]->v_package[4]);
! 473: sc->sc_pss[i].pss_status = aml_val2int(
! 474: res.v_package[i]->v_package[5]);
! 475: }
! 476: aml_freevalue(&res);
! 477:
! 478: sc->sc_pss_len = res.length;
! 479:
! 480: return (0);
! 481: }
! 482:
! 483: int
! 484: acpicpu_fetch_pss(struct acpicpu_pss **pss) {
! 485: /*XXX: According to the ACPI spec in an SMP system all processors
! 486: * are supposed to support the same states. For now we prey
! 487: * the bios ensures this...
! 488: */
! 489: struct acpicpu_softc *sc;
! 490:
! 491: sc = acpicpu_sc[0];
! 492: if (!sc) {
! 493: printf("couldnt fetch acpicpu_softc\n");
! 494: return 0;
! 495: }
! 496: *pss = sc->sc_pss;
! 497:
! 498: return sc->sc_pss_len;
! 499: }
! 500:
! 501: int
! 502: acpicpu_notify(struct aml_node *node, int notify_type, void *arg)
! 503: {
! 504: struct acpicpu_softc *sc = arg;
! 505:
! 506: dnprintf(10, "acpicpu_notify: %.2x %s\n", notify_type,
! 507: sc->sc_devnode->name);
! 508:
! 509: switch (notify_type) {
! 510: case 0x80: /* _PPC changed, retrieve new values */
! 511: acpicpu_getpct(sc);
! 512: acpicpu_getpss(sc);
! 513: if (sc->sc_notify)
! 514: sc->sc_notify(sc->sc_pss, sc->sc_pss_len);
! 515: break;
! 516: default:
! 517: printf("%s: unhandled cpu event %x\n", DEVNAME(sc),
! 518: notify_type);
! 519: break;
! 520: }
! 521:
! 522: return (0);
! 523: }
! 524:
! 525: void
! 526: acpicpu_set_notify(void (*func)(struct acpicpu_pss *, int)) {
! 527: struct acpicpu_softc *sc;
! 528:
! 529: sc = acpicpu_sc[0];
! 530: if (sc != NULL)
! 531: sc->sc_notify = func;
! 532: }
! 533:
! 534: void
! 535: acpicpu_setperf(int level) {
! 536: struct acpicpu_softc *sc;
! 537: struct acpicpu_pss *pss = NULL;
! 538: int idx;
! 539: u_int32_t stat_as, ctrl_as, stat_len, ctrl_len;
! 540: u_int32_t status = 0;
! 541:
! 542: sc = acpicpu_sc[cpu_number()];
! 543:
! 544: dnprintf(10, "%s: acpicpu setperf level %d\n",
! 545: sc->sc_devnode->name, level);
! 546:
! 547: if (level < 0 || level > 100) {
! 548: dnprintf(10, "%s: acpicpu setperf illegal percentage\n",
! 549: sc->sc_devnode->name);
! 550: return;
! 551: }
! 552:
! 553: idx = (sc->sc_pss_len - 1) - (level / (100 / sc->sc_pss_len));
! 554: if (idx < 0)
! 555: idx = 0; /* compensate */
! 556: if (idx > sc->sc_pss_len) {
! 557: /* XXX should never happen */
! 558: printf("%s: acpicpu setperf index out of range\n",
! 559: sc->sc_devnode->name);
! 560: return;
! 561: }
! 562:
! 563: dnprintf(10, "%s: acpicpu setperf index %d\n",
! 564: sc->sc_devnode->name, idx);
! 565:
! 566: pss = &sc->sc_pss[idx];
! 567:
! 568: /* if not set assume single 32 bit access */
! 569: stat_as = sc->sc_pct.pct_status.grd_gas.register_bit_width / 8;
! 570: if (stat_as == 0)
! 571: stat_as = 4;
! 572: ctrl_as = sc->sc_pct.pct_ctrl.grd_gas.register_bit_width / 8;
! 573: if (ctrl_as == 0)
! 574: ctrl_as = 4;
! 575: stat_len = sc->sc_pct.pct_status.grd_gas.access_size;
! 576: if (stat_len == 0)
! 577: stat_len = stat_as;
! 578: ctrl_len = sc->sc_pct.pct_ctrl.grd_gas.access_size;
! 579: if (ctrl_len == 0)
! 580: ctrl_len = ctrl_as;
! 581:
! 582: #ifdef ACPI_DEBUG
! 583: /* keep this for now since we will need this for debug in the field */
! 584: printf("0 status: %x %llx %u %u ctrl: %x %llx %u %u\n",
! 585: sc->sc_pct.pct_status.grd_gas.address_space_id,
! 586: sc->sc_pct.pct_status.grd_gas.address,
! 587: stat_as, stat_len,
! 588: sc->sc_pct.pct_ctrl.grd_gas.address_space_id,
! 589: sc->sc_pct.pct_ctrl.grd_gas.address,
! 590: ctrl_as, ctrl_len);
! 591: #endif
! 592: acpi_gasio(sc->sc_acpi, ACPI_IOREAD,
! 593: sc->sc_pct.pct_status.grd_gas.address_space_id,
! 594: sc->sc_pct.pct_status.grd_gas.address, stat_as, stat_len,
! 595: &status);
! 596: dnprintf(20, "status: %u <- %u\n", status, pss->pss_status);
! 597:
! 598: /* Are we already at the requested frequency? */
! 599: if (status == pss->pss_status)
! 600: return;
! 601:
! 602: acpi_gasio(sc->sc_acpi, ACPI_IOWRITE,
! 603: sc->sc_pct.pct_ctrl.grd_gas.address_space_id,
! 604: sc->sc_pct.pct_ctrl.grd_gas.address, ctrl_as, ctrl_len,
! 605: &pss->pss_ctrl);
! 606: dnprintf(20, "pss_ctrl: %x\n", pss->pss_ctrl);
! 607:
! 608: acpi_gasio(sc->sc_acpi, ACPI_IOREAD,
! 609: sc->sc_pct.pct_status.grd_gas.address_space_id,
! 610: sc->sc_pct.pct_status.grd_gas.address, stat_as, stat_as,
! 611: &status);
! 612: dnprintf(20, "3 status: %d\n", status);
! 613:
! 614: /* Did the transition succeed? */
! 615: if (status == pss->pss_status)
! 616: cpuspeed = pss->pss_core_freq;
! 617: else
! 618: printf("%s: acpicpu setperf failed to alter frequency\n",
! 619: sc->sc_devnode->name);
! 620: }
CVSweb