[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     ! 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