From ca3f42bc92c8b47bd2a43dffa6b7c4ce20e01407 Mon Sep 17 00:00:00 2001 From: jhb Date: Sat, 23 Aug 2008 12:53:42 +0000 Subject: 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 --- sys/i386/cpufreq/est.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 88 insertions(+), 1 deletion(-) (limited to 'sys/i386/cpufreq') 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 #include "cpufreq_if.h" +#include #include #include @@ -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) { -- cgit v1.1