summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2012-03-10 18:56:16 +0000
committermav <mav@FreeBSD.org>2012-03-10 18:56:16 +0000
commit4be9351f8bd44209a6e7521658b3da16c1951098 (patch)
treef960e0018bf89aa5ad1591c9545f9d50434c6bfb
parent49831084fc545dca70c5b7d523832649aadfeb7c (diff)
downloadFreeBSD-src-4be9351f8bd44209a6e7521658b3da16c1951098.zip
FreeBSD-src-4be9351f8bd44209a6e7521658b3da16c1951098.tar.gz
Revert r175376 and tune cpufreq(4) frequency comparison logic instead.
Instead of using 25MHz equality threshold, look for the nearest value when handling dev.cpu.0.freq sysctl and for exact match when it is expected. ACPI may report extra level with frequency 1MHz above the nominal to control Intel Turbo Boost operation. It is not a bug, but feature: dev.cpu.0.freq_levels: 2934/106000 2933/95000 2800/82000 ... In this case value 2933 means 2.93GHz, but 2934 means 3.2-3.6GHz. I've found that my Core i7-870 based system has Intel Turbo Boost disabled by default and without this change it was absolutely invisible and hard to control. MFC after: 2 weeks
-rw-r--r--sys/kern/kern_cpu.c31
1 files changed, 10 insertions, 21 deletions
diff --git a/sys/kern/kern_cpu.c b/sys/kern/kern_cpu.c
index c32a63c..6df4d3f 100644
--- a/sys/kern/kern_cpu.c
+++ b/sys/kern/kern_cpu.c
@@ -312,7 +312,7 @@ cf_set_method(device_t dev, const struct cf_level *level, int priority)
}
/* If already at this level, just return. */
- if (CPUFREQ_CMP(sc->curr_level.total_set.freq, level->total_set.freq)) {
+ if (sc->curr_level.total_set.freq == level->total_set.freq) {
CF_DEBUG("skipping freq %d, same as current level %d\n",
level->total_set.freq, sc->curr_level.total_set.freq);
goto skip;
@@ -471,7 +471,7 @@ cf_get_method(device_t dev, struct cf_level *level)
if (CPUFREQ_DRV_GET(devs[n], &set) != 0)
continue;
for (i = 0; i < count; i++) {
- if (CPUFREQ_CMP(set.freq, levels[i].total_set.freq)) {
+ if (set.freq == levels[i].total_set.freq) {
sc->curr_level = levels[i];
break;
}
@@ -627,16 +627,6 @@ cf_levels_method(device_t dev, struct cf_level *levels, int *count)
/* Finally, output the list of levels. */
i = 0;
TAILQ_FOREACH(lev, &sc->all_levels, link) {
- /*
- * Skip levels that are too close in frequency to the
- * previous levels. Some systems report bogus duplicate
- * settings (i.e., for acpi_perf).
- */
- if (i > 0 && CPUFREQ_CMP(lev->total_set.freq,
- levels[i - 1].total_set.freq)) {
- sc->all_count--;
- continue;
- }
/* Skip levels that have a frequency that is too low. */
if (lev->total_set.freq < cf_lowest_freq) {
@@ -870,7 +860,7 @@ cpufreq_curr_sysctl(SYSCTL_HANDLER_ARGS)
{
struct cpufreq_softc *sc;
struct cf_level *levels;
- int count, devcount, error, freq, i, n;
+ int best, count, diff, bdiff, devcount, error, freq, i, n;
device_t *devs;
devs = NULL;
@@ -902,17 +892,16 @@ cpufreq_curr_sysctl(SYSCTL_HANDLER_ARGS)
"cpufreq: need to increase CF_MAX_LEVELS\n");
break;
}
+ best = 0;
+ bdiff = 1 << 30;
for (i = 0; i < count; i++) {
- if (CPUFREQ_CMP(levels[i].total_set.freq, freq)) {
- error = CPUFREQ_SET(devs[n], &levels[i],
- CPUFREQ_PRIO_USER);
- break;
+ diff = abs(levels[i].total_set.freq - freq);
+ if (diff < bdiff) {
+ bdiff = diff;
+ best = i;
}
}
- if (i == count) {
- error = EINVAL;
- break;
- }
+ error = CPUFREQ_SET(devs[n], &levels[best], CPUFREQ_PRIO_USER);
}
out:
OpenPOWER on IntegriCloud