root/arch/i386/pci/piixpcib.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. piixpcib_int15_gsic_call
  2. piixpcib_set_ownership
  3. piixpcib_configure_speedstep
  4. piixpcib_match
  5. piixpcib_attach
  6. piixpcib_getset_state
  7. piixpcib_setperf

    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 }

/* [<][>][^][v][top][bottom][index][help] */