[BACK]Return to acpicpu.c CVS log [TXT][DIR] Up to [local] / sys / dev / acpi

Annotation of sys/dev/acpi/acpicpu.c, Revision 1.1.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