Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 21 Jan 2009 15:01:36 +0000 (UTC)
From:      John Baldwin <jhb@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org
Subject:   svn commit: r187529 - in stable/7/sys: . contrib/pf dev/ath/ath_hal dev/cxgb i386/cpufreq
Message-ID:  <200901211501.n0LF1agR080911@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jhb
Date: Wed Jan 21 15:01:36 2009
New Revision: 187529
URL: http://svn.freebsd.org/changeset/base/187529

Log:
  MFC: If we are unable to obtain a frequency list from either ACPI or the
  static tables, then attempt to build a simple list containing just the high
  and low frequencies if the hw.est.msr_info tunable is set to 1.  By default
  this is disabled.

Modified:
  stable/7/sys/   (props changed)
  stable/7/sys/contrib/pf/   (props changed)
  stable/7/sys/dev/ath/ath_hal/   (props changed)
  stable/7/sys/dev/cxgb/   (props changed)
  stable/7/sys/i386/cpufreq/est.c

Modified: stable/7/sys/i386/cpufreq/est.c
==============================================================================
--- stable/7/sys/i386/cpufreq/est.c	Wed Jan 21 14:51:38 2009	(r187528)
+++ stable/7/sys/i386/cpufreq/est.c	Wed Jan 21 15:01:36 2009	(r187529)
@@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/systm.h>
 
 #include "cpufreq_if.h"
+#include <machine/clock.h>
 #include <machine/md_var.h>
 #include <machine/specialreg.h>
 
@@ -71,6 +72,7 @@ typedef struct {
 struct est_softc {
 	device_t	dev;
 	int		acpi_settings;
+	int		msr_settings;
 	freq_info	*freq_list;
 };
 
@@ -92,6 +94,8 @@ struct est_softc {
 
 const char intel_id[] = "GenuineIntel";
 const char centaur_id[] = "CentaurHauls";
+static int msr_info_enabled = 0;
+TUNABLE_INT("hw.est.msr_info", &msr_info_enabled);
 
 /* Default bus clock value for Centrino processors. */
 #define INTEL_BUS_CLK		100
@@ -898,6 +902,7 @@ static int	est_detach(device_t parent);
 static int	est_get_info(device_t dev);
 static int	est_acpi_info(device_t dev, freq_info **freqs);
 static int	est_table_info(device_t dev, uint64_t msr, freq_info **freqs);
+static int	est_msr_info(device_t dev, uint64_t msr, freq_info **freqs);
 static freq_info *est_get_current(freq_info *freq_list);
 static int	est_settings(device_t dev, struct cf_setting *sets, int *count);
 static int	est_set(device_t dev, const struct cf_setting *set);
@@ -1039,7 +1044,7 @@ est_detach(device_t dev)
 		return (error);
 
 	sc = device_get_softc(dev);
-	if (sc->acpi_settings)
+	if (sc->acpi_settings || sc->msr_settings)
 		free(sc->freq_list, M_DEVBUF);
 	return (0);
 }
@@ -1063,6 +1068,8 @@ est_get_info(device_t dev)
 	error = est_table_info(dev, msr, &sc->freq_list);
 	if (error)
 		error = est_acpi_info(dev, &sc->freq_list);
+	if (error)
+		error = est_msr_info(dev, msr, &sc->freq_list);
 
 	if (error) {
 		printf(
@@ -1168,6 +1175,91 @@ est_table_info(device_t dev, uint64_t ms
 	return (0);
 }
 
+static int
+bus_speed_ok(int bus)
+{
+
+	switch (bus) {
+	case 100:
+	case 133:
+	case 333:
+		return (1);
+	default:
+		return (0);
+	}
+}
+
+/*
+ * Flesh out a simple rate table containing the high and low frequencies
+ * based on the current clock speed and the upper 32 bits of the MSR.
+ */
+static int
+est_msr_info(device_t dev, uint64_t msr, freq_info **freqs)
+{
+	struct est_softc *sc;
+	freq_info *fp;
+	int bus, freq, volts;
+	uint16_t id;
+
+	if (!msr_info_enabled)
+		return (EOPNOTSUPP);
+
+	/* Figure out the bus clock. */
+	freq = tsc_freq / 1000000;
+	id = msr >> 32;
+	bus = freq / (id >> 8);
+	device_printf(dev, "Guessed bus clock (high) of %d MHz\n", bus);
+	if (!bus_speed_ok(bus)) {
+		/* We may be running on the low frequency. */
+		id = msr >> 48;
+		bus = freq / (id >> 8);
+		device_printf(dev, "Guessed bus clock (low) of %d MHz\n", bus);
+		if (!bus_speed_ok(bus))
+			return (EOPNOTSUPP);
+		
+		/* Calculate high frequency. */
+		id = msr >> 32;
+		freq = ((id >> 8) & 0xff) * bus;
+	}
+
+	/* Fill out a new freq table containing just the high and low freqs. */
+	sc = device_get_softc(dev);
+	fp = malloc(sizeof(freq_info) * 3, M_DEVBUF, M_WAITOK | M_ZERO);
+
+	/* First, the high frequency. */
+	volts = id & 0xff;
+	if (volts != 0) {
+		volts <<= 4;
+		volts += 700;
+	}
+	fp[0].freq = freq;
+	fp[0].volts = volts;
+	fp[0].id16 = id;
+	fp[0].power = CPUFREQ_VAL_UNKNOWN;
+	device_printf(dev, "Guessed high setting of %d MHz @ %d Mv\n", freq,
+	    volts);
+
+	/* Second, the low frequency. */
+	id = msr >> 48;
+	freq = ((id >> 8) & 0xff) * bus;
+	volts = id & 0xff;
+	if (volts != 0) {
+		volts <<= 4;
+		volts += 700;
+	}
+	fp[1].freq = freq;
+	fp[1].volts = volts;
+	fp[1].id16 = id;
+	fp[1].power = CPUFREQ_VAL_UNKNOWN;
+	device_printf(dev, "Guessed low setting of %d MHz @ %d Mv\n", freq,
+	    volts);
+
+	/* Table is already terminated due to M_ZERO. */
+	sc->msr_settings = TRUE;
+	*freqs = fp;
+	return (0);
+}
+
 static void
 est_get_id16(uint16_t *id16_p)
 {



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200901211501.n0LF1agR080911>