summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_cpu.c
diff options
context:
space:
mode:
authornjl <njl@FreeBSD.org>2005-02-15 07:43:48 +0000
committernjl <njl@FreeBSD.org>2005-02-15 07:43:48 +0000
commit5cd9fb8f6ce21f7176161abbb37102691daf739b (patch)
treebadedb782572a31b0802fd10c338ac10ac2900dd /sys/kern/kern_cpu.c
parent463116c7e031cff2ebe9ee834bf86458be8c4595 (diff)
downloadFreeBSD-src-5cd9fb8f6ce21f7176161abbb37102691daf739b.zip
FreeBSD-src-5cd9fb8f6ce21f7176161abbb37102691daf739b.tar.gz
When dealing with systems with no absolute drivers attached, only calibrate
the rate for the 100% state once. Afterwards, use that value for deriving states. This should fix the problem where the calibrated frequency was different once a switch was done, giving a different set of levels each time. Also, properly search for the right cpufreqX device when detaching.
Diffstat (limited to 'sys/kern/kern_cpu.c')
-rw-r--r--sys/kern/kern_cpu.c32
1 files changed, 22 insertions, 10 deletions
diff --git a/sys/kern/kern_cpu.c b/sys/kern/kern_cpu.c
index df88473..d51dcb5 100644
--- a/sys/kern/kern_cpu.c
+++ b/sys/kern/kern_cpu.c
@@ -62,6 +62,7 @@ struct cpufreq_softc {
int saved_priority;
struct cf_level_lst all_levels;
int all_count;
+ int max_mhz;
device_t dev;
struct sysctl_ctx_list sysctl_ctx;
};
@@ -123,6 +124,7 @@ cpufreq_attach(device_t dev)
TAILQ_INIT(&sc->all_levels);
sc->curr_level.total_set.freq = CPUFREQ_VAL_UNKNOWN;
sc->saved_level.total_set.freq = CPUFREQ_VAL_UNKNOWN;
+ sc->max_mhz = CPUFREQ_VAL_UNKNOWN;
/*
* Only initialize one set of sysctls for all CPUs. In the future,
@@ -430,16 +432,22 @@ cf_levels_method(device_t dev, struct cf_level *levels, int *count)
goto out;
}
- /* If there are no absolute levels, create a fake one at 100%. */
+ /*
+ * If there are no absolute levels, create a fake one at 100%. We
+ * then cache the clockrate for later use as our base frequency.
+ *
+ * XXX This assumes that the first time through, if we only have
+ * relative drivers, the CPU is currently running at 100%.
+ */
if (TAILQ_EMPTY(&sc->all_levels)) {
- bzero(&sets[0], sizeof(*sets));
- pc = cpu_get_pcpu(dev);
- if (pc == NULL) {
- error = ENXIO;
- goto out;
+ if (sc->max_mhz == CPUFREQ_VAL_UNKNOWN) {
+ pc = cpu_get_pcpu(dev);
+ cpu_est_clockrate(pc->pc_cpuid, &rate);
+ sc->max_mhz = rate / 1000000;
}
- cpu_est_clockrate(pc->pc_cpuid, &rate);
- sets[0].freq = rate / 1000000;
+ memset(&sets[0], CPUFREQ_VAL_UNKNOWN, sizeof(*sets));
+ sets[0].freq = sc->max_mhz;
+ sets[0].dev = NULL;
error = cpufreq_insert_abs(sc, sets, 1);
if (error)
goto out;
@@ -737,6 +745,7 @@ out:
int
cpufreq_register(device_t dev)
{
+ struct cpufreq_softc *sc;
device_t cf_dev, cpu_dev;
/*
@@ -744,8 +753,11 @@ cpufreq_register(device_t dev)
* must offer the same levels and be switched at the same time.
*/
cpu_dev = device_get_parent(dev);
- if (device_find_child(cpu_dev, "cpufreq", -1))
+ if ((cf_dev = device_find_child(cpu_dev, "cpufreq", -1))) {
+ sc = device_get_softc(cf_dev);
+ sc->max_mhz = CPUFREQ_VAL_UNKNOWN;
return (0);
+ }
/* Add the child device and possibly sysctls. */
cf_dev = BUS_ADD_CHILD(cpu_dev, 0, "cpufreq", -1);
@@ -771,7 +783,7 @@ cpufreq_unregister(device_t dev)
error = device_get_children(device_get_parent(dev), &devs, &devcount);
if (error)
return (error);
- cf_dev = devclass_get_device(cpufreq_dc, 0);
+ cf_dev = device_find_child(device_get_parent(dev), "cpufreq", -1);
cfcount = 0;
for (i = 0; i < devcount; i++) {
if (!device_is_attached(devs[i]))
OpenPOWER on IntegriCloud