From 67c8649f7fb5783bd325211ad1edaf06018fcb3e Mon Sep 17 00:00:00 2001 From: Nate Lawson Date: Tue, 15 Feb 2005 07:43:48 +0000 Subject: [PATCH] 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. --- sys/kern/kern_cpu.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/sys/kern/kern_cpu.c b/sys/kern/kern_cpu.c index df884737fb27..d51dcb50fb4e 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]))