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

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

1.1       nbrk        1: /*     $OpenBSD: ichpcib.c,v 1.19 2007/06/02 18:39:57 jsg Exp $        */
                      2: /*
                      3:  * Copyright (c) 2004 Alexander Yurchenko <grange@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: /*
                     19:  * Special driver for the Intel ICHx/ICHx-M LPC bridges that attaches
                     20:  * instead of pcib(4). In addition to the core pcib(4) functionality this
                     21:  * driver provides support for the Intel SpeedStep technology and
                     22:  * power management timer.
                     23:  */
                     24:
                     25: #include <sys/param.h>
                     26: #include <sys/systm.h>
                     27: #include <sys/device.h>
                     28: #include <sys/sysctl.h>
                     29: #ifdef __HAVE_TIMECOUNTER
                     30: #include <sys/timetc.h>
                     31: #endif
                     32:
                     33: #include <machine/bus.h>
                     34:
                     35: #include <dev/pci/pcireg.h>
                     36: #include <dev/pci/pcivar.h>
                     37: #include <dev/pci/pcidevs.h>
                     38:
                     39: #include <dev/pci/ichreg.h>
                     40:
                     41: #include <machine/cpu.h>
                     42: #include <machine/cpufunc.h>
                     43:
                     44: struct ichpcib_softc {
                     45:        struct device sc_dev;
                     46:
                     47:        bus_space_tag_t sc_pm_iot;
                     48:        bus_space_handle_t sc_pm_ioh;
                     49: };
                     50:
                     51: int    ichpcib_match(struct device *, void *, void *);
                     52: void   ichpcib_attach(struct device *, struct device *, void *);
                     53:
                     54: int    ichss_present(struct pci_attach_args *);
                     55: void   ichss_setperf(int);
                     56:
                     57: /* arch/i386/pci/pcib.c */
                     58: void    pcibattach(struct device *, struct device *, void *);
                     59:
                     60: #ifdef __HAVE_TIMECOUNTER
                     61: u_int  ichpcib_get_timecount(struct timecounter *tc);
                     62:
                     63: struct timecounter ichpcib_timecounter = {
                     64:        ichpcib_get_timecount,  /* get_timecount */
                     65:        0,                      /* no poll_pps */
                     66:        0xffffff,               /* counter_mask */
                     67:        3579545,                /* frequency */
                     68:        "ICHPM",                /* name */
                     69:        1000                    /* quality */
                     70: };
                     71: #endif /* __HAVE_TIMECOUNTER */
                     72:
                     73: struct cfattach ichpcib_ca = {
                     74:        sizeof(struct ichpcib_softc),
                     75:        ichpcib_match,
                     76:        ichpcib_attach
                     77: };
                     78:
                     79: struct cfdriver ichpcib_cd = {
                     80:        NULL, "ichpcib", DV_DULL
                     81: };
                     82:
                     83: #ifndef SMALL_KERNEL
                     84: static const char p4hint[] = "Mobile Intel(R) Pentium(R) 4";
                     85: struct ichpcib_softc *ichss_sc;
                     86: extern int setperf_prio;
                     87: #endif /* !SMALL_KERNEL */
                     88:
                     89: const struct pci_matchid ichpcib_devices[] = {
                     90:        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_6300ESB_LPC },
                     91:        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_6321ESB_LPC },
                     92:        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AA_LPC },
                     93:        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AB_LPC },
                     94:        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801BA_LPC },
                     95:        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801BAM_LPC },
                     96:        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801CA_LPC },
                     97:        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801CAM_LPC },
                     98:        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801DB_LPC },
                     99:        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801DBM_LPC },
                    100:        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801E_LPC },
                    101:        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801EB_LPC },
                    102:        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801FB_LPC },
                    103:        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801FBM_LPC },
                    104:        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801GB_LPC },
                    105:        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801GBM_LPC },
                    106:        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801GH_LPC },
                    107:        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801GHM_LPC },
                    108:        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801H_LPC },
                    109:        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801HBM_LPC }
                    110: };
                    111:
                    112: int
                    113: ichpcib_match(struct device *parent, void *match, void *aux)
                    114: {
                    115:        if (pci_matchbyid((struct pci_attach_args *)aux, ichpcib_devices,
                    116:            sizeof(ichpcib_devices) / sizeof(ichpcib_devices[0])))
                    117:                return (2);     /* supersede pcib(4) */
                    118:        return (0);
                    119: }
                    120:
                    121: void
                    122: ichpcib_attach(struct device *parent, struct device *self, void *aux)
                    123: {
                    124:        struct ichpcib_softc *sc = (struct ichpcib_softc *)self;
                    125:        struct pci_attach_args *pa = aux;
                    126:        pcireg_t cntl, pmbase;
                    127:
                    128:        /* Check if power management I/O space is enabled */
                    129:        cntl = pci_conf_read(pa->pa_pc, pa->pa_tag, ICH_ACPI_CNTL);
                    130:        if ((cntl & ICH_ACPI_CNTL_ACPI_EN) == 0) {
                    131:                printf(": PM disabled");
                    132:                goto corepcib;
                    133:        }
                    134:
                    135:        /* Map power management I/O space */
                    136:        sc->sc_pm_iot = pa->pa_iot;
                    137:        pmbase = pci_conf_read(pa->pa_pc, pa->pa_tag, ICH_PMBASE);
                    138:        if (bus_space_map(sc->sc_pm_iot, PCI_MAPREG_IO_ADDR(pmbase),
                    139:            ICH_PMSIZE, 0, &sc->sc_pm_ioh) != 0)
                    140:                goto corepcib;
                    141:
                    142: #ifdef __HAVE_TIMECOUNTER
                    143:        /* Register new timecounter */
                    144:        ichpcib_timecounter.tc_priv = sc;
                    145:        tc_init(&ichpcib_timecounter);
                    146:
                    147:        printf(": %s-bit timer at %lluHz",
                    148:            (ichpcib_timecounter.tc_counter_mask == 0xffffffff ? "32" : "24"),
                    149:            (unsigned long long)ichpcib_timecounter.tc_frequency);
                    150: #endif /* __HAVE_TIMECOUNTER */
                    151:
                    152: #ifndef SMALL_KERNEL
                    153:        /* Check for SpeedStep */
                    154:        if (ichss_present(pa)) {
                    155:                printf(": SpeedStep");
                    156:
                    157:                /* Enable SpeedStep */
                    158:                pci_conf_write(pa->pa_pc, pa->pa_tag, ICH_GEN_PMCON1,
                    159:                    pci_conf_read(pa->pa_pc, pa->pa_tag, ICH_GEN_PMCON1) |
                    160:                        ICH_GEN_PMCON1_SS_EN);
                    161:
                    162:                /* Hook into hw.setperf sysctl */
                    163:                ichss_sc = sc;
                    164:                cpu_setperf = ichss_setperf;
                    165:                setperf_prio = 2;
                    166:        }
                    167: #endif /* !SMALL_KERNEL */
                    168:
                    169: corepcib:
                    170:        /* Provide core pcib(4) functionality */
                    171:        pcibattach(parent, self, aux);
                    172: }
                    173:
                    174: #ifndef SMALL_KERNEL
                    175: int
                    176: ichss_present(struct pci_attach_args *pa)
                    177: {
                    178:        pcitag_t br_tag;
                    179:        pcireg_t br_id, br_class;
                    180:        struct cpu_info *ci;
                    181:        int family, model, stepping, brandid;
                    182:
                    183:        if (setperf_prio > 2)
                    184:                return (0);
                    185:
                    186:        ci = curcpu();
                    187:        family = (ci->ci_signature >> 8) & 15;
                    188:        model = (ci->ci_signature >> 4) & 15;
                    189:        stepping = ci->ci_signature & 15;
                    190:        brandid = cpu_miscinfo & 0xff; /* XXX should put this in ci */
                    191:
                    192:        /*
                    193:         * This form of SpeedStep works only on Intel Mobile Pentium 4.
                    194:         * Intel Celeron processors don't support it.  However, they
                    195:         * can be coupled with ICH southbridges that do, causing false
                    196:         * positives.  So we ensure that we are running on Intel Mobile
                    197:         * Pentium 4.
                    198:         * This heuristic comes from the Linux speedstep-ich driver.
                    199:         */
                    200:        if (!(family == 15 && model == 2 &&
                    201:            ((stepping == 4 && (brandid == 14 || brandid == 15)) ||
                    202:            (stepping == 7 && brandid == 14) ||
                    203:            (stepping == 9 && (brandid == 14 || strncasecmp(cpu_model, p4hint,
                    204:            sizeof(p4hint) - 1) == 0)))))
                    205:                return (0);
                    206:
                    207:        if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_82801DBM_LPC ||
                    208:            PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_82801CAM_LPC)
                    209:                return (1);
                    210:        if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_82801BAM_LPC) {
                    211:                /*
                    212:                 * Old revisions of the 82815 hostbridge found on
                    213:                 * Dell Inspirons 8000 and 8100 don't support
                    214:                 * SpeedStep.
                    215:                 */
                    216:                /*
                    217:                 * XXX: dev 0 func 0 is not always a hostbridge,
                    218:                 * should be converted to use pchb(4) hook.
                    219:                 */
                    220:                br_tag = pci_make_tag(pa->pa_pc, pa->pa_bus, 0, 0);
                    221:                br_id = pci_conf_read(pa->pa_pc, br_tag, PCI_ID_REG);
                    222:                br_class = pci_conf_read(pa->pa_pc, br_tag, PCI_CLASS_REG);
                    223:
                    224:                if (PCI_PRODUCT(br_id) == PCI_PRODUCT_INTEL_82815_FULL_HUB &&
                    225:                    PCI_REVISION(br_class) < 5)
                    226:                        return (0);
                    227:                return (1);
                    228:        }
                    229:
                    230:        return (0);
                    231: }
                    232:
                    233: void
                    234: ichss_setperf(int level)
                    235: {
                    236:        struct ichpcib_softc *sc = ichss_sc;
                    237:        u_int8_t state, ostate, cntl;
                    238:        int s;
                    239:
                    240: #ifdef DIAGNOSTIC
                    241:        if (sc == NULL) {
                    242:                printf("%s: no ichss_sc", __func__);
                    243:                return;
                    244:        }
                    245: #endif
                    246:
                    247:        s = splhigh();
                    248:        state = bus_space_read_1(sc->sc_pm_iot, sc->sc_pm_ioh, ICH_PM_SS_CNTL);
                    249:        ostate = state;
                    250:
                    251:        /* Only two states are available */
                    252:        if (level <= 50)
                    253:                state |= ICH_PM_SS_STATE_LOW;
                    254:        else
                    255:                state &= ~ICH_PM_SS_STATE_LOW;
                    256:
                    257:        /*
                    258:         * An Intel SpeedStep technology transition _always_ occur on
                    259:         * writes to the ICH_PM_SS_CNTL register, even if the value
                    260:         * written is the same as the previous value. So do the write
                    261:         * only if the state has changed.
                    262:         */
                    263:        if (state != ostate) {
                    264:                /* Disable bus mastering arbitration */
                    265:                cntl = bus_space_read_1(sc->sc_pm_iot, sc->sc_pm_ioh,
                    266:                    ICH_PM_CNTL);
                    267:                bus_space_write_1(sc->sc_pm_iot, sc->sc_pm_ioh, ICH_PM_CNTL,
                    268:                    cntl | ICH_PM_ARB_DIS);
                    269:
                    270:                /* Do the transition */
                    271:                bus_space_write_1(sc->sc_pm_iot, sc->sc_pm_ioh, ICH_PM_SS_CNTL,
                    272:                    state);
                    273:
                    274:                /* Restore bus mastering arbitration state */
                    275:                bus_space_write_1(sc->sc_pm_iot, sc->sc_pm_ioh, ICH_PM_CNTL,
                    276:                    cntl);
                    277:
                    278: #ifdef I686_CPU
                    279:                if (update_cpuspeed != NULL)
                    280:                        update_cpuspeed();
                    281: #endif
                    282:        }
                    283:        splx(s);
                    284: }
                    285: #endif /* !SMALL_KERNEL */
                    286:
                    287: #ifdef __HAVE_TIMECOUNTER
                    288: u_int
                    289: ichpcib_get_timecount(struct timecounter *tc)
                    290: {
                    291:        struct ichpcib_softc *sc = tc->tc_priv;
                    292:        u_int u1, u2, u3;
                    293:
                    294:        u2 = bus_space_read_4(sc->sc_pm_iot, sc->sc_pm_ioh, ICH_PM_TMR);
                    295:        u3 = bus_space_read_4(sc->sc_pm_iot, sc->sc_pm_ioh, ICH_PM_TMR);
                    296:        do {
                    297:                u1 = u2;
                    298:                u2 = u3;
                    299:                u3 = bus_space_read_4(sc->sc_pm_iot, sc->sc_pm_ioh,
                    300:                    ICH_PM_TMR);
                    301:        } while (u1 > u2 || u2 > u3);
                    302:
                    303:        return (u2);
                    304: }
                    305: #endif /* __HAVE_TIMECOUNTER */

CVSweb