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