Annotation of sys/arch/i386/pci/piixpcib.c, Revision 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(®s, 0, sizeof(struct kvm86regs));
! 148: regs.eax = PIIXPCIB_IST_CALL;
! 149: regs.edx = PIIXPCIB_ISGE;
! 150: kvm86_simplecall(0x15, ®s);
! 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