summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/arch/i386/pci/pcib.c136
-rw-r--r--sys/dev/pci/ichreg.h48
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_ */