diff --git a/sys/kern/kern_cpu.c b/sys/kern/kern_cpu.c index 7b0b58891b32..9f7f6156704d 100644 --- a/sys/kern/kern_cpu.c +++ b/sys/kern/kern_cpu.c @@ -158,12 +158,16 @@ cpufreq_attach(device_t dev) CF_MTX_INIT(&sc->lock); sc->curr_level.total_set.freq = CPUFREQ_VAL_UNKNOWN; SLIST_INIT(&sc->saved_freq); - /* Try to get current CPU freq to use it as maximum later if needed */ - pc = cpu_get_pcpu(dev); - if (cpu_est_clockrate(pc->pc_cpuid, &rate) == 0) - sc->max_mhz = rate / 1000000; - else - sc->max_mhz = CPUFREQ_VAL_UNKNOWN; + /* Try to get nominal CPU freq to use it as maximum later if needed */ + sc->max_mhz = cpu_get_nominal_mhz(dev); + /* If that fails, try to measure the current rate */ + if (sc->max_mhz <= 0) { + pc = cpu_get_pcpu(dev); + if (cpu_est_clockrate(pc->pc_cpuid, &rate) == 0) + sc->max_mhz = rate / 1000000; + else + sc->max_mhz = CPUFREQ_VAL_UNKNOWN; + } /* * Only initialize one set of sysctls for all CPUs. In the future, @@ -581,15 +585,20 @@ cf_levels_method(device_t dev, struct cf_level *levels, int *count) /* * 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)) { if (sc->max_mhz == CPUFREQ_VAL_UNKNOWN) { - pc = cpu_get_pcpu(dev); - cpu_est_clockrate(pc->pc_cpuid, &rate); - sc->max_mhz = rate / 1000000; + sc->max_mhz = cpu_get_nominal_mhz(dev); + /* + * If the CPU can't report a rate for 100%, hope + * the CPU is running at its nominal rate right now, + * and use that instead. + */ + if (sc->max_mhz <= 0) { + pc = cpu_get_pcpu(dev); + cpu_est_clockrate(pc->pc_cpuid, &rate); + sc->max_mhz = rate / 1000000; + } } memset(&sets[0], CPUFREQ_VAL_UNKNOWN, sizeof(*sets)); sets[0].freq = sc->max_mhz; diff --git a/sys/sys/cpu.h b/sys/sys/cpu.h index d282d300695f..c16091e1504e 100644 --- a/sys/sys/cpu.h +++ b/sys/sys/cpu.h @@ -36,6 +36,7 @@ */ #define CPU_IVAR_PCPU 1 +#define CPU_IVAR_NOMINAL_MHZ 2 static __inline struct pcpu *cpu_get_pcpu(device_t dev) { @@ -44,6 +45,15 @@ static __inline struct pcpu *cpu_get_pcpu(device_t dev) return ((struct pcpu *)v); } +static __inline int32_t cpu_get_nominal_mhz(device_t dev) +{ + uintptr_t v = 0; + if (BUS_READ_IVAR(device_get_parent(dev), dev, + CPU_IVAR_NOMINAL_MHZ, &v) != 0) + return (-1); + return ((int32_t)v); +} + /* * CPU frequency control interface. */