diff options
-rw-r--r-- | sys/arch/i386/pci/pcib.c | 136 | ||||
-rw-r--r-- | sys/dev/pci/ichreg.h | 48 |
2 files changed, 182 insertions, 2 deletions
diff --git a/sys/arch/i386/pci/pcib.c b/sys/arch/i386/pci/pcib.c index 3fd4c4e64d1..e7a96d1b9f8 100644 --- a/sys/arch/i386/pci/pcib.c +++ b/sys/arch/i386/pci/pcib.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pcib.c,v 1.10 2003/05/18 21:08:01 henning Exp $ */ +/* $OpenBSD: pcib.c,v 1.11 2004/02/19 21:35:56 grange Exp $ */ /* $NetBSD: pcib.c,v 1.6 1997/06/06 23:29:16 thorpej Exp $ */ /*- @@ -41,6 +41,7 @@ #include <sys/param.h> #include <sys/systm.h> #include <sys/device.h> +#include <sys/sysctl.h> #include <machine/bus.h> #include <dev/isa/isavar.h> @@ -50,6 +51,8 @@ #include <dev/pci/pcidevs.h> +#include <dev/pci/ichreg.h> + #include "isa.h" #include "pcibios.h" #if NPCIBIOS > 0 @@ -61,8 +64,20 @@ void pcibattach(struct device *, struct device *, void *); void pcib_callback(struct device *); int pcib_print(void *, const char *); +int ichss_match(void *); +int ichss_attach(struct device *, void *); +int ichss_setperf(int); + +struct pcib_softc { + struct device sc_dev; + + /* For power management capable bridges */ + bus_space_tag_t sc_pmt; + bus_space_handle_t sc_pmh; +}; + struct cfattach pcib_ca = { - sizeof(struct device), pcibmatch, pcibattach + sizeof(struct pcib_softc), pcibmatch, pcibattach }; struct cfdriver pcib_cd = { @@ -106,6 +121,14 @@ pcibattach(parent, self, aux) struct device *parent, *self; void *aux; { +#ifndef SMALL_KERNEL + /* + * Detect and activate SpeedStep on ICHx-M chipsets. + */ + if (ichss_match(aux) && ichss_attach(self, aux) == 0) + printf(": SpeedStep"); +#endif + /* * Cannot attach isa bus now; must postpone for various reasons */ @@ -147,3 +170,112 @@ pcib_print(aux, pnp) printf("isa at %s", pnp); return (UNCONF); } + +#ifndef SMALL_KERNEL +static void *ichss_cookie; /* XXX */ + +int +ichss_match(void *aux) +{ + struct pci_attach_args *pa = aux; + pcitag_t br_tag; + pcireg_t br_id, br_class; + + if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_82801DBM_LPC || + PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_82801CAM_LPC) + return (1); + if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_82801BAM_LPC) { + /* + * Old revisions of the 82815 hostbridge found on + * Dell Inspirons 8000 and 8100 don't support + * SpeedStep. + */ + /* XXX: dev 0 func 0 is not always a hostbridge */ + br_tag = pci_make_tag(pa->pa_pc, pa->pa_bus, 0, 0); + br_id = pci_conf_read(pa->pa_pc, br_tag, PCI_ID_REG); + br_class = pci_conf_read(pa->pa_pc, br_tag, PCI_CLASS_REG); + + if (PCI_PRODUCT(br_id) == PCI_PRODUCT_INTEL_82815_FULL_HUB && + PCI_REVISION(br_class) < 5) + return (0); + return (1); + } + + return (0); +} + +int +ichss_attach(struct device *self, void *aux) +{ + struct pcib_softc *sc = (struct pcib_softc *)self; + struct pci_attach_args *pa = aux; + pcireg_t pmbase; + + /* Map power management I/O space */ + sc->sc_pmt = pa->pa_iot; + pmbase = pci_conf_read(pa->pa_pc, pa->pa_tag, ICH_PMBASE); + if (bus_space_map(sc->sc_pmt, PCI_MAPREG_IO_ADDR(pmbase), + ICH_PMSIZE, 0, &sc->sc_pmh) != 0) + return (1); + + /* Enable SpeedStep */ + pci_conf_write(pa->pa_pc, pa->pa_tag, ICH_GEN_PMCON1, + pci_conf_read(pa->pa_pc, pa->pa_tag, ICH_GEN_PMCON1) | + ICH_GEN_PMCON1_SS_EN); + + /* Hook into hw.setperf sysctl */ + ichss_cookie = sc; + cpu_setperf = ichss_setperf; + + return (0); +} + +int +ichss_setperf(int level) +{ + struct pcib_softc *sc = ichss_cookie; + u_int8_t state, ostate, cntl; + int s; + +#ifdef DIAGNOSTIC + if (sc == NULL) { + printf("%s: no cookie", __func__); + return (EFAULT); + } +#endif + + s = splhigh(); + state = bus_space_read_1(sc->sc_pmt, sc->sc_pmh, ICH_PM_SS_CNTL); + ostate = state; + + /* Only two states are available */ + if (level < 50) + state |= ICH_PM_SS_STATE_LOW; + else + state &= ~ICH_PM_SS_STATE_LOW; + + /* + * An Intel SpeedStep technology transition _always_ occur on + * writes to the ICH_PM_SS_CNTL register, even if the value + * written is the same as the previous value. So do the write + * only if the state has changed. + */ + if (state != ostate) { + /* Disable bus mastering arbitration */ + cntl = bus_space_read_1(sc->sc_pmt, sc->sc_pmh, ICH_PM_CNTL); + bus_space_write_1(sc->sc_pmt, sc->sc_pmh, ICH_PM_CNTL, + cntl | ICH_PM_ARB_DIS); + + /* Do the transition */ + bus_space_write_1(sc->sc_pmt, sc->sc_pmh, ICH_PM_SS_CNTL, + state); + + /* Restore bus mastering arbitration state */ + bus_space_write_1(sc->sc_pmt, sc->sc_pmh, ICH_PM_CNTL, + cntl); + } + splx(s); + + return (0); +} +#endif /* !SMALL_KERNEL */ diff --git a/sys/dev/pci/ichreg.h b/sys/dev/pci/ichreg.h new file mode 100644 index 00000000000..7a17f5cb87d --- /dev/null +++ b/sys/dev/pci/ichreg.h @@ -0,0 +1,48 @@ +/* $OpenBSD: ichreg.h,v 1.1 2004/02/19 21:35:56 grange Exp $ */ +/* + * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _DEV_PCI_ICHREG_H_ +#define _DEV_PCI_ICHREG_H_ + +/* + * Intel ICH registers definitions + */ + +/* + * LPC interface bridge registers + */ + +/* + * PCI configuration registers + */ +#define ICH_PMBASE 0x40 /* ACPI base address */ +#define ICH_GEN_PMCON1 0xa0 /* general PM configuration */ +/* ICHx-M only */ +#define ICH_GEN_PMCON1_SS_EN 0x08 /* enable SpeedStep */ + +#define ICH_PMSIZE 128 /* ACPI space size */ + +/* + * Power management I/O registers + */ +/* ICHx-M only */ +#define ICH_PM_CNTL 0x20 /* power management control */ +#define ICH_PM_ARB_DIS 0x01 /* disable arbiter */ +#define ICH_PM_SS_CNTL 0x50 /* SpeedStep control */ +#define ICH_PM_SS_STATE_LOW 0x01 /* low power state */ + +#endif /* !_DEV_PCI_ICHREG_H_ */ |