svn commit: r193155 - in head/sys: kern sys

Nathan Whitehorn nwhitehorn at FreeBSD.org
Sun May 31 08:59:16 UTC 2009


Author: nwhitehorn
Date: Sun May 31 08:59:15 2009
New Revision: 193155
URL: http://svn.freebsd.org/changeset/base/193155

Log:
  Provide a new CPU device driver ivar to report the nominal speed of the
  CPU, if available. This is meant to solve the issue of cpufreq misreporting
  speeds on CPUs that boot in a reduced power mode and have only relative
  speed control.

Modified:
  head/sys/kern/kern_cpu.c
  head/sys/sys/cpu.h

Modified: head/sys/kern/kern_cpu.c
==============================================================================
--- head/sys/kern/kern_cpu.c	Sun May 31 08:11:39 2009	(r193154)
+++ head/sys/kern/kern_cpu.c	Sun May 31 08:59:15 2009	(r193155)
@@ -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
 	/*
 	 * 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;

Modified: head/sys/sys/cpu.h
==============================================================================
--- head/sys/sys/cpu.h	Sun May 31 08:11:39 2009	(r193154)
+++ head/sys/sys/cpu.h	Sun May 31 08:59:15 2009	(r193155)
@@ -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_pcp
 	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.
  */


More information about the svn-src-head mailing list