summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornjl <njl@FreeBSD.org>2005-02-14 18:16:35 +0000
committernjl <njl@FreeBSD.org>2005-02-14 18:16:35 +0000
commit6e0f1dda0ae84a33bf74a1c070707d25c0c66a90 (patch)
tree348ee5486643f8f6b24eb93b1f61677c55683016
parent08dca4373d4a1de0c7b4d7059f1f6d889bf2f13d (diff)
downloadFreeBSD-src-6e0f1dda0ae84a33bf74a1c070707d25c0c66a90.zip
FreeBSD-src-6e0f1dda0ae84a33bf74a1c070707d25c0c66a90.tar.gz
Implement priorities. This allows a driver (say, for cooling purposes) to
override the current freq level temporarily and restore it when the higher priority condition is past. Note that only the first overridden value is saved. Callers pass NULL to CPUFREQ_SET to restore the saved level. Priorities are not yet used so this commit should have no effect.
-rw-r--r--sys/kern/kern_cpu.c42
1 files changed, 38 insertions, 4 deletions
diff --git a/sys/kern/kern_cpu.c b/sys/kern/kern_cpu.c
index ff1d006..85b33d1 100644
--- a/sys/kern/kern_cpu.c
+++ b/sys/kern/kern_cpu.c
@@ -57,9 +57,11 @@ __FBSDID("$FreeBSD$");
struct cpufreq_softc {
struct cf_level curr_level;
- int priority;
- int all_count;
+ int curr_priority;
+ struct cf_level saved_level;
+ int saved_priority;
struct cf_level_lst all_levels;
+ int all_count;
device_t dev;
struct sysctl_ctx_list sysctl_ctx;
};
@@ -120,6 +122,7 @@ cpufreq_attach(device_t dev)
sysctl_ctx_init(&sc->sysctl_ctx);
TAILQ_INIT(&sc->all_levels);
sc->curr_level.total_set.freq = CPUFREQ_VAL_UNKNOWN;
+ sc->saved_level.total_set.freq = CPUFREQ_VAL_UNKNOWN;
/*
* Only initialize one set of sysctls for all CPUs. In the future,
@@ -185,6 +188,21 @@ cf_set_method(device_t dev, const struct cf_level *level, int priority)
if (strcmp(timecounter->tc_name, "TSC") == 0)
return (EBUSY);
+ /*
+ * If the caller didn't specify a level and one is saved, prepare to
+ * restore the saved level. If none has been saved, return an error.
+ * If they did specify one, but the requested level has a lower
+ * priority, don't allow the new level right now.
+ */
+ if (level == NULL) {
+ if (sc->saved_level.total_set.freq != CPUFREQ_VAL_UNKNOWN) {
+ level = &sc->saved_level;
+ priority = sc->saved_priority;
+ } else
+ return (ENXIO);
+ } else if (priority < sc->curr_priority)
+ return (EPERM);
+
/* If already at this level, just return. */
if (CPUFREQ_CMP(sc->curr_level.total_set.freq, level->total_set.freq))
return (0);
@@ -226,9 +244,25 @@ cf_set_method(device_t dev, const struct cf_level *level, int priority)
}
}
- /* Record the current level. */
+ /* If we were restoring a saved state, reset it to "unused". */
+ if (level == &sc->saved_level) {
+ sc->saved_level.total_set.freq = CPUFREQ_VAL_UNKNOWN;
+ sc->saved_priority = 0;
+ }
+
+ /*
+ * Before recording the current level, check if we're going to a
+ * higher priority and have not saved a level yet. If so, save the
+ * previous level and priority.
+ */
+ if (sc->curr_level.total_set.freq != CPUFREQ_VAL_UNKNOWN &&
+ sc->saved_level.total_set.freq == CPUFREQ_VAL_UNKNOWN &&
+ priority > sc->curr_priority) {
+ sc->saved_level = sc->curr_level;
+ sc->saved_priority = sc->curr_priority;
+ }
sc->curr_level = *level;
- sc->priority = priority;
+ sc->curr_priority = priority;
error = 0;
out:
OpenPOWER on IntegriCloud