[BACK]Return to piixpcib.c CVS log [TXT][DIR] Up to [local] / sys / arch / i386 / pci

Annotation of sys/arch/i386/pci/piixpcib.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: piixpcib.c,v 1.2 2007/05/29 02:40:24 tom Exp $ */
                      2:
                      3: /*
                      4:  * Copyright (c) 2007 Stefan Sperling <stsp@stsp.in-berlin.de>
                      5:  * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org>
                      6:  *
                      7:  * Permission to use, copy, modify, and distribute this software for any
                      8:  * purpose with or without fee is hereby granted, provided that the above
                      9:  * copyright notice and this permission notice appear in all copies.
                     10:  *
                     11:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     12:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     13:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     14:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     15:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     16:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     17:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     18:  *
                     19:  *-
                     20:  * Copyright (c) 2004, 2006 The NetBSD Foundation, Inc.
                     21:  * All rights reserved.
                     22:  *
                     23:  * This code is derived from software contributed to The NetBSD Foundation
                     24:  * by Minoura Makoto, Matthew R. Green, and Jared D. McNeill.
                     25:  *
                     26:  * Redistribution and use in source and binary forms, with or without
                     27:  * modification, are permitted provided that the following conditions
                     28:  * are met:
                     29:  * 1. Redistributions of source code must retain the above copyright
                     30:  *    notice, this list of conditions and the following disclaimer.
                     31:  * 2. Redistributions in binary form must reproduce the above copyright
                     32:  *    notice, this list of conditions and the following disclaimer in the
                     33:  *    documentation and/or other materials provided with the distribution.
                     34:  * 3. All advertising materials mentioning features or use of this software
                     35:  *    must display the following acknowledgement:
                     36:  *        This product includes software developed by the NetBSD
                     37:  *        Foundation, Inc. and its contributors.
                     38:  * 4. Neither the name of The NetBSD Foundation nor the names of its
                     39:  *    contributors may be used to endorse or promote products derived
                     40:  *    from this software without specific prior written permission.
                     41:  *
                     42:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     43:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     44:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     45:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     46:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     47:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     48:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     49:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     50:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     51:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     52:  * POSSIBILITY OF SUCH DAMAGE.
                     53:  */
                     54:
                     55: /*
                     56:  * Special driver for the Intel PIIX4 bridges that attaches
                     57:  * instead of pcib(4). In addition to the core pcib(4) functionality this
                     58:  * driver provides support for Intel SpeedStep technology present in
                     59:  * some Pentium III CPUs.
                     60:  */
                     61:
                     62: #include <sys/param.h>
                     63: #include <sys/systm.h>
                     64: #include <sys/device.h>
                     65: #include <sys/sysctl.h>
                     66:
                     67: #include <machine/bus.h>
                     68:
                     69: #include <dev/pci/pcireg.h>
                     70: #include <dev/pci/pcivar.h>
                     71: #include <dev/pci/pcidevs.h>
                     72:
                     73: #include <machine/cpu.h>
                     74: #include <machine/cpufunc.h>
                     75: #include <machine/kvm86.h>
                     76:
                     77: /* 0x47534943 == "ISGE" ('Intel Speedstep Gate E') */
                     78: #define        PIIXPCIB_ISGE                   0x47534943
                     79: #define        PIIXPCIB_IST_CALL               0x0000e980
                     80: #define        PIIXPCIB_GSIC_CMD               0x82
                     81: #define        PIIXPCIB_DEFAULT_COMMAND        \
                     82:        ((PIIXPCIB_ISGE & 0xffffff00) | (PIIXPCIB_GSIC_CMD & 0xff))
                     83:
                     84: #define        PIIXPCIB_DEFAULT_SMI_PORT       0xb2
                     85: #define        PIIXPCIB_DEFAULT_SMI_DATA       0xb3
                     86:
                     87: #define        PIIXPCIB_GETSTATE               1
                     88: #define        PIIXPCIB_SETSTATE               2
                     89: #define        PIIXPCIB_SPEEDSTEP_HIGH         0
                     90: #define        PIIXPCIB_SPEEDSTEP_LOW          1
                     91:
                     92: struct piixpcib_softc {
                     93:        struct device sc_dev;
                     94:
                     95:        int             sc_sig;
                     96:        int             sc_smi_port;
                     97:        int             sc_smi_data;
                     98:        int             sc_command;
                     99:        int             sc_flags;
                    100:
                    101:        int             state;
                    102: };
                    103:
                    104: int    piixpcib_match(struct device *, void *, void *);
                    105: void   piixpcib_attach(struct device *, struct device *, void *);
                    106:
                    107: void   piixpcib_setperf(int);
                    108: int    piixpcib_cpuspeed(int *);
                    109:
                    110: int    piixpcib_set_ownership(struct piixpcib_softc *);
                    111: int    piixpcib_configure_speedstep(struct piixpcib_softc *);
                    112: int    piixpcib_getset_state(struct piixpcib_softc *, int *, int);
                    113: void   piixpcib_int15_gsic_call(struct piixpcib_softc *);
                    114:
                    115: /* arch/i386/pci/pcib.c */
                    116: extern void    pcibattach(struct device *, struct device *, void *);
                    117:
                    118: /* arch/i386/i386/machdep.c */
                    119: #if !defined(SMALL_KERNEL) && defined(I686_CPU)
                    120: extern void    p3_update_cpuspeed(void);
                    121: #endif
                    122:
                    123: struct cfattach piixpcib_ca = {
                    124:        sizeof(struct piixpcib_softc),
                    125:        piixpcib_match,
                    126:        piixpcib_attach
                    127: };
                    128:
                    129: struct cfdriver piixpcib_cd = {
                    130:        NULL, "piixpcib", DV_DULL
                    131: };
                    132:
                    133: struct piixpcib_softc *piixpcib_sc;
                    134: extern int setperf_prio;
                    135:
                    136: const struct pci_matchid piixpcib_devices[] = {
                    137:        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371AB_ISA}, /* PIIX4 */
                    138:        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82440MX_PM},  /* PIIX4 in MX440 */
                    139: };
                    140:
                    141: void
                    142: piixpcib_int15_gsic_call(struct piixpcib_softc *sc)
                    143: {
                    144:        struct kvm86regs regs;
                    145:        int cmd;
                    146:
                    147:        memset(&regs, 0, sizeof(struct kvm86regs));
                    148:        regs.eax = PIIXPCIB_IST_CALL;
                    149:        regs.edx = PIIXPCIB_ISGE;
                    150:        kvm86_simplecall(0x15, &regs);
                    151:
                    152:        if (regs.eax == PIIXPCIB_ISGE) {
                    153:                sc->sc_sig = regs.eax;
                    154:                sc->sc_smi_port = regs.ebx & 0xff;
                    155:
                    156:                cmd = (regs.ebx >> 16) & 0xff;
                    157:                /* GSIC may return cmd 0x80, should be PIIXPCIB_GSIC_CMD */
                    158:                if (cmd == 0x80)
                    159:                        cmd = PIIXPCIB_GSIC_CMD;
                    160:                sc->sc_command = (sc->sc_sig & 0xffffff00) | (cmd & 0xff);
                    161:
                    162:                sc->sc_smi_data = regs.ecx;
                    163:                sc->sc_flags = regs.edx;
                    164:        }
                    165: }
                    166:
                    167: int
                    168: piixpcib_set_ownership(struct piixpcib_softc *sc)
                    169: {
                    170:        int rv;
                    171:        paddr_t pmagic;
                    172:        char magic[] = "Copyright (c) 1999 Intel Corporation";
                    173:
                    174:        pmap_extract(pmap_kernel(), (vaddr_t)magic, &pmagic);
                    175:
                    176:        __asm __volatile(
                    177:                "movl $0, %%edi\n\t"
                    178:                "out %%al, (%%dx)\n"
                    179:                : "=D" (rv)
                    180:                : "a" (sc->sc_command),
                    181:                  "b" (0),
                    182:                  "c" (0),
                    183:                  "d" (sc->sc_smi_port),
                    184:                  "S" (pmagic)
                    185:        );
                    186:
                    187:        return (rv ? ENXIO : 0);
                    188: }
                    189:
                    190: int
                    191: piixpcib_configure_speedstep(struct piixpcib_softc *sc)
                    192: {
                    193:        int rv;
                    194:
                    195:        sc->sc_sig = -1;
                    196:
                    197:        /* setup some defaults */
                    198:        sc->sc_smi_port = PIIXPCIB_DEFAULT_SMI_PORT;
                    199:        sc->sc_smi_data = PIIXPCIB_DEFAULT_SMI_DATA;
                    200:        sc->sc_command = PIIXPCIB_DEFAULT_COMMAND;
                    201:        sc->sc_flags = 0;
                    202:
                    203:        piixpcib_int15_gsic_call(sc);
                    204:
                    205:        /* If signature doesn't match, bail out */
                    206:        if (sc->sc_sig != PIIXPCIB_ISGE)
                    207:                return ENODEV;
                    208:
                    209:        if (piixpcib_set_ownership(sc) != 0) {
                    210:                printf(": unable to claim ownership from BIOS, "
                    211:                    "SpeedStep disabled");
                    212:                return ENXIO;
                    213:        }
                    214:
                    215:        rv = piixpcib_getset_state(sc, &sc->state, PIIXPCIB_GETSTATE);
                    216:        if (rv != 0) {
                    217:                printf(": cannot determine CPU power state, "
                    218:                    "SpeedStep disabled");
                    219:                return ENXIO;
                    220:        }
                    221:
                    222:        /* save the sc for IO tag/handle */
                    223:        piixpcib_sc = sc;
                    224:
                    225:        return 0;
                    226: }
                    227:
                    228: int
                    229: piixpcib_match(struct device *parent, void *match, void *aux)
                    230: {
                    231:        if (pci_matchbyid((struct pci_attach_args *)aux, piixpcib_devices,
                    232:            sizeof(piixpcib_devices) / sizeof(piixpcib_devices[0])))
                    233:                return (2);     /* supersede pcib(4) */
                    234:        return (0);
                    235: }
                    236:
                    237: void
                    238: piixpcib_attach(struct device *parent, struct device *self, void *aux)
                    239: {
                    240:        struct piixpcib_softc *sc = (struct piixpcib_softc *)self;
                    241:
                    242:        if (setperf_prio < 2) {
                    243:                /* Set up SpeedStep. */
                    244:                if (piixpcib_configure_speedstep(sc) == 0) {
                    245:                        printf(": SpeedStep");
                    246:
                    247:                        /* Hook into hw.setperf sysctl */
                    248:                        cpu_setperf = piixpcib_setperf;
                    249:                        setperf_prio = 2;
                    250:                }
                    251:        }
                    252:
                    253:        /* Provide core pcib(4) functionality */
                    254:        pcibattach(parent, self, aux);
                    255: }
                    256:
                    257: int
                    258: piixpcib_getset_state(struct piixpcib_softc *sc, int *state, int function)
                    259: {
                    260:        int new_state;
                    261:        int rv;
                    262:        int eax;
                    263:
                    264: #ifdef DIAGNOSTIC
                    265:        if (function != PIIXPCIB_GETSTATE &&
                    266:            function != PIIXPCIB_SETSTATE) {
                    267:                printf("%s: %s called with invalid function %d\n",
                    268:                    sc->sc_dev.dv_xname, __func__, function);
                    269:                return EINVAL;
                    270:        }
                    271: #endif
                    272:
                    273:        __asm __volatile(
                    274:                "movl $0, %%edi\n\t"
                    275:                "out %%al, (%%dx)\n"
                    276:                : "=a" (eax),
                    277:                  "=b" (new_state),
                    278:                  "=D" (rv)
                    279:                : "a" (sc->sc_command),
                    280:                  "b" (function),
                    281:                  "c" (*state),
                    282:                  "d" (sc->sc_smi_port),
                    283:                  "S" (0)
                    284:        );
                    285:
                    286:        *state = new_state & 1;
                    287:
                    288:        switch (function) {
                    289:        case PIIXPCIB_GETSTATE:
                    290:                if (eax)
                    291:                        return ENXIO;
                    292:                break;
                    293:        case PIIXPCIB_SETSTATE:
                    294:                if (rv)
                    295:                        return ENXIO;
                    296:                break;
                    297:        }
                    298:
                    299:        return 0;
                    300: }
                    301:
                    302: void
                    303: piixpcib_setperf(int level)
                    304: {
                    305:        struct piixpcib_softc *sc;
                    306:        int new_state;
                    307:        int tries, rv, s;
                    308:
                    309:        sc = piixpcib_sc;
                    310:
                    311: #ifdef DIAGNOSTIC
                    312:        if (sc == NULL) {
                    313:                printf("%s: no cookie", __func__);
                    314:                return;
                    315:        }
                    316: #endif
                    317:
                    318:        /* Only two states are available */
                    319:        if (level <= 50)
                    320:                new_state = PIIXPCIB_SPEEDSTEP_LOW;
                    321:        else
                    322:                new_state = PIIXPCIB_SPEEDSTEP_HIGH;
                    323:
                    324:        if (sc->state == new_state)
                    325:                return;
                    326:
                    327:        tries = 5;
                    328:        s = splhigh();
                    329:
                    330:        do {
                    331:                rv = piixpcib_getset_state(sc, &new_state,
                    332:                    PIIXPCIB_SETSTATE);
                    333:                if (rv)
                    334:                        delay(200);
                    335:        } while (rv && --tries);
                    336:
                    337:        splx(s);
                    338:
                    339: #ifdef DIAGNOSTIC
                    340:        if (rv)
                    341:                printf("%s: setting CPU power state failed",
                    342:                    sc->sc_dev.dv_xname);
                    343: #endif
                    344:
                    345:        sc->state = new_state;
                    346:
                    347:        /* Force update of hw.cpuspeed.
                    348:         *
                    349:         * XXX: First generation SpeedStep is only present in some
                    350:         * Pentium III CPUs and we are lacking a reliable method to
                    351:         * determine CPU freqs corresponding to low and high power state.
                    352:         *
                    353:         * And yes, I've tried it the way the Linux speedstep-smi
                    354:         * driver does it, thank you very much. It doesn't work
                    355:         * half the time (my machine has more than 4Mhz ;-) and
                    356:         * even crashes some machines without specific workarounds.
                    357:         *
                    358:         * So call p3_update_cpuspeed() from arch/i386/i386/machdep.c
                    359:         * instead. Works fine on my Thinkpad X21.
                    360:         *
                    361:         * BUT: Apparently, if the bus is busy, the transition may be
                    362:         * delayed and retried under control of evil SMIs we cannot
                    363:         * control. So busy-wait a short while before updating hw.cpuspeed
                    364:         * to decrease chances of picking up the old CPU speed.
                    365:         * There seems to be no reliable fix for this.
                    366:         */
                    367:        delay(200);
                    368: #if !defined(SMALL_KERNEL) && defined(I686_CPU)
                    369:        p3_update_cpuspeed();
                    370: #endif
                    371: }

CVSweb