Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/i386/pci implement ICH-based Intel SpeedStep(TM), b...
details: https://anonhg.NetBSD.org/src/rev/37910fc51031
branches: trunk
changeset: 568799:37910fc51031
user: mrg <mrg%NetBSD.org@localhost>
date: Sat Jul 31 17:32:31 2004 +0000
description:
implement ICH-based Intel SpeedStep(TM), based on both the linux and
freebsd drivers for the same. if found and supported, export a
"machdep.speedstep_state" sysctl that can be set to "0" (low) or "1"
(high).
tested on a dell inspiron 8500 (supported, working) and a dual P4
system (supports ichlpcib not speedstep, comes up properly disabled.)
diffstat:
sys/arch/i386/pci/ichlpcib.c | 156 +++++++++++++++++++++++++++++++++++++++++-
1 files changed, 151 insertions(+), 5 deletions(-)
diffs (203 lines):
diff -r ed17bb4fde77 -r 37910fc51031 sys/arch/i386/pci/ichlpcib.c
--- a/sys/arch/i386/pci/ichlpcib.c Sat Jul 31 17:28:36 2004 +0000
+++ b/sys/arch/i386/pci/ichlpcib.c Sat Jul 31 17:32:31 2004 +0000
@@ -1,11 +1,11 @@
-/* $NetBSD: ichlpcib.c,v 1.5 2004/04/04 15:16:38 kochi Exp $ */
+/* $NetBSD: ichlpcib.c,v 1.6 2004/07/31 17:32:31 mrg Exp $ */
/*-
* Copyright (c) 2004 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
- * by Minoura Makoto.
+ * by Minoura Makoto and Matthew R. Green.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -41,16 +41,18 @@
*
* LPC Interface Bridge is basically a pcib (PCI-ISA Bridge), but has
* some power management and monitoring functions.
- * Currently we support the watchdog timer.
+ * Currently we support the watchdog timer, and SpeedStep on some
+ * systems.
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ichlpcib.c,v 1.5 2004/04/04 15:16:38 kochi Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ichlpcib.c,v 1.6 2004/07/31 17:32:31 mrg Exp $");
#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
+#include <sys/sysctl.h>
#include <machine/bus.h>
#include <dev/pci/pcivar.h>
@@ -79,6 +81,12 @@
static int tcotimer_setmode(struct sysmon_wdog *);
static int tcotimer_tickle(struct sysmon_wdog *);
+static void speedstep_configure(struct lpcib_softc *,
+ struct pci_attach_args *);
+static int speedstep_sysctl_helper(SYSCTLFN_ARGS);
+
+struct lpcib_softc *speedstep_cookie; /* XXX */
+
/* Defined in arch/i386/pci/pcib.c. */
extern void pcibattach(struct device *, struct device *, void *);
@@ -126,8 +134,11 @@
pcibattach(parent, self, aux);
- /* Currently we use TCO timer feature only... */
+ /* Set up the TCO (watchdog). */
tcotimer_configure(sc, pa);
+
+ /* Set up SpeedStep. */
+ speedstep_configure(sc, pa);
}
/*
@@ -265,3 +276,138 @@
return 0;
}
+
+/*
+ * Intel ICH SpeedStep support.
+ */
+#define SS_READ(sc, reg) \
+ bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, (reg))
+#define SS_WRITE(sc, reg, val) \
+ bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
+
+/*
+ * Linux driver says that SpeedStep on older chipsets cause
+ * lockups on Dell Inspiron 8000 and 8100.
+ */
+static int
+speedstep_bad_hb_check(struct pci_attach_args *pa)
+{
+
+ if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_82815_FULL_HUB &&
+ PCI_REVISION(pa->pa_class) < 5)
+ return (1);
+
+ return (0);
+}
+
+static void
+speedstep_configure(struct lpcib_softc *sc, struct pci_attach_args *pa)
+{
+ struct sysctlnode *node, *ssnode;
+ int rv;
+
+ /* Supported on ICH2-M, ICH3-M and ICH4-M. */
+ if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_82801DB_ISA ||
+ PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_82801CAM_LPC ||
+ (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_82801BAM_LPC &&
+ pci_find_device(pa, speedstep_bad_hb_check) == 0)) {
+ u_int8_t pmcon;
+
+ /* Enable SpeedStep if it isn't already enabled. */
+ pmcon = pci_conf_read(pa->pa_pc, pa->pa_tag,
+ LPCIB_PCI_GEN_PMCON_1);
+ if ((pmcon & LPCIB_PCI_GEN_PMCON_1_SS_EN) == 0)
+ pci_conf_write(pa->pa_pc, pa->pa_tag,
+ LPCIB_PCI_GEN_PMCON_1,
+ pmcon | LPCIB_PCI_GEN_PMCON_1_SS_EN);
+
+ /* Put in machdep.speedstep_state (0 for low, 1 for high). */
+ if ((rv = sysctl_createv(NULL, 0, NULL, &node,
+ CTLFLAG_PERMANENT, CTLTYPE_NODE, "machdep", NULL,
+ NULL, 0, NULL, 0, CTL_MACHDEP, CTL_EOL)) != 0)
+ goto err;
+
+ /* CTLFLAG_ANYWRITE? kernel option like EST? */
+ if ((rv = sysctl_createv(NULL, 0, &node, &ssnode,
+ CTLFLAG_READWRITE, CTLTYPE_INT, "speedstep_state", NULL,
+ speedstep_sysctl_helper, 0, NULL, 0, CTL_CREATE,
+ CTL_EOL)) != 0)
+ goto err;
+
+ /* XXX save the sc for IO tag/handle */
+ speedstep_cookie = sc;
+
+ printf("%s: SpeedStep enabled\n", sc->sc_dev.dv_xname);
+ } else
+ printf("%s: No SpeedStep\n", sc->sc_dev.dv_xname);
+
+ return;
+
+err:
+ aprint_normal("%s: sysctl_createv failed (rv = %d)\n", __func__, rv);
+}
+
+/*
+ * get/set the SpeedStep state: 0 == low power, 1 == high power.
+ */
+static int
+speedstep_sysctl_helper(SYSCTLFN_ARGS)
+{
+ struct sysctlnode node;
+ struct lpcib_softc *sc = speedstep_cookie;
+ u_int8_t state, state2;
+ int ostate, nstate, s, error = 0;
+
+ /*
+ * We do the dance with spl's to avoid being at high ipl during
+ * sysctl_lookup() which can both copyin and copyout.
+ */
+ s = splserial();
+ state = SS_READ(sc, LPCIB_PM_SS_CNTL);
+ splx(s);
+ if ((state & LPCIB_PM_SS_STATE_LOW) == 0)
+ ostate = 1;
+ else
+ ostate = 0;
+ nstate = ostate;
+
+ node = *rnode;
+ node.sysctl_data = &nstate;
+
+ error = sysctl_lookup(SYSCTLFN_CALL(&node));
+ if (error || newp == NULL)
+ goto out;
+
+ /* Only two states are available */
+ if (nstate != 0 && nstate != 1) {
+ error = EINVAL;
+ goto out;
+ }
+
+ s = splserial();
+ state2 = SS_READ(sc, LPCIB_PM_SS_CNTL);
+ if ((state2 & LPCIB_PM_SS_STATE_LOW) == 0)
+ ostate = 1;
+ else
+ ostate = 0;
+ if (ostate != nstate)
+ {
+ u_int8_t cntl;
+
+ if (nstate == 0)
+ state2 |= LPCIB_PM_SS_STATE_LOW;
+ else
+ state2 &= ~LPCIB_PM_SS_STATE_LOW;
+
+ /*
+ * Must disable bus master arbitration during the change.
+ */
+ cntl = SS_READ(sc, LPCIB_PM_CTRL);
+ SS_WRITE(sc, LPCIB_PM_CTRL, cntl | LPCIB_PM_SS_CNTL_ARB_DIS);
+ SS_WRITE(sc, LPCIB_PM_SS_CNTL, state2);
+ SS_WRITE(sc, LPCIB_PM_CTRL, cntl);
+ }
+ splx(s);
+out:
+ return (error);
+}
Home |
Main Index |
Thread Index |
Old Index