summaryrefslogtreecommitdiffstats
path: root/sys/i386/cpufreq
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2008-08-23 12:53:42 +0000
committerjhb <jhb@FreeBSD.org>2008-08-23 12:53:42 +0000
commitca3f42bc92c8b47bd2a43dffa6b7c4ce20e01407 (patch)
tree887dc2c99f72f29454b4519778abd50cc8e2a7a9 /sys/i386/cpufreq
parentd4ceeb8daaa8fac2179d8cbf275d1e05ab67c564 (diff)
downloadFreeBSD-src-ca3f42bc92c8b47bd2a43dffa6b7c4ce20e01407.zip
FreeBSD-src-ca3f42bc92c8b47bd2a43dffa6b7c4ce20e01407.tar.gz
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 based on the current CPU frequency calculated during boot and the contents of the MSR. MFC after: 1 month
Diffstat (limited to 'sys/i386/cpufreq')
-rw-r--r--sys/i386/cpufreq/est.c89
1 files changed, 88 insertions, 1 deletions
diff --git a/sys/i386/cpufreq/est.c b/sys/i386/cpufreq/est.c
index 8732cbd..594199e 100644
--- a/sys/i386/cpufreq/est.c
+++ b/sys/i386/cpufreq/est.c
@@ -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;
};
@@ -898,6 +900,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);
@@ -1035,7 +1038,7 @@ est_detach(device_t dev)
struct est_softc *sc;
sc = device_get_softc(dev);
- if (sc->acpi_settings)
+ if (sc->acpi_settings || sc->msr_settings)
free(sc->freq_list, M_DEVBUF);
#endif
return (ENXIO);
@@ -1060,6 +1063,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(
@@ -1165,6 +1170,88 @@ est_table_info(device_t dev, uint64_t msr, freq_info **freqs)
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;
+
+ /* 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)
{
OpenPOWER on IntegriCloud