powernow regression in 8-STABLE

Jung-uk Kim jkim at FreeBSD.org
Fri Jul 22 21:58:19 UTC 2011


On Friday 22 July 2011 07:13 am, Callum Gibson wrote:
> On 21Jul11 17:53, Jung-uk Kim wrote:
> }>
> }>
> http://members.optusnet.com.au/callumgibson/boot_verboser_nousb.out
> }> and dev.cpu.0.freq reappears! Spooky. Is that a solution or a }>
> workaround? I noticed this disables usb keyboard support at the }>
> boot menus.
> }
> }It is a workaround.  Please try the attached patch.
>
> Sorry, no improvement that I can see. See verbose output:
>
> http://members.optusnet.com.au/callumgibson/boot_verboser2.out

Please try the attached patch.  If it doesn't work, I need to see 
"acpidump -dt" output.

Jung-uk Kim
-------------- next part --------------
Index: sys/kern/kern_cpu.c
===================================================================
--- sys/kern/kern_cpu.c	(revision 224271)
+++ sys/kern/kern_cpu.c	(working copy)
@@ -145,9 +145,7 @@ static int
 cpufreq_attach(device_t dev)
 {
 	struct cpufreq_softc *sc;
-	struct pcpu *pc;
 	device_t parent;
-	uint64_t rate;
 	int numdevs;
 
 	CF_DEBUG("initializing %s\n", device_get_nameunit(dev));
@@ -157,18 +155,7 @@ cpufreq_attach(device_t dev)
 	sysctl_ctx_init(&sc->sysctl_ctx);
 	TAILQ_INIT(&sc->all_levels);
 	CF_MTX_INIT(&sc->lock);
-	sc->curr_level.total_set.freq = CPUFREQ_VAL_UNKNOWN;
 	SLIST_INIT(&sc->saved_freq);
-	/* 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,
@@ -500,6 +487,7 @@ cf_get_method(device_t dev, struct cf_level *level
 			goto out;
 		}
 	}
+	CF_DEBUG("get freq failed, estimated freq %d\n", (int)rate);
 	error = ENXIO;
 
 out:
@@ -551,17 +539,23 @@ cf_levels_method(device_t dev, struct cf_level *le
 		 * provide settings for informational purposes only.
 		 */
 		error = CPUFREQ_DRV_TYPE(devs[i], &type);
-		if (error || (type & CPUFREQ_FLAG_INFO_ONLY)) {
-			if (error == 0) {
-				CF_DEBUG("skipping info-only driver %s\n",
-				    device_get_nameunit(devs[i]));
-			}
+		if (error)
 			continue;
-		}
 		set_count = MAX_SETTINGS;
 		error = CPUFREQ_DRV_SETTINGS(devs[i], sets, &set_count);
 		if (error || set_count == 0)
 			continue;
+		if ((type & CPUFREQ_TYPE_MASK) == CPUFREQ_TYPE_ABSOLUTE &&
+		    sc->max_mhz < sets[0].freq) {
+			CF_DEBUG("setting max freq %d from %s\n",
+			    sets[0].freq, device_get_nameunit(devs[i]));
+			sc->max_mhz = sets[0].freq;
+		}
+		if ((type & CPUFREQ_FLAG_INFO_ONLY) != 0) {
+			CF_DEBUG("skipping info-only driver %s\n",
+			    device_get_nameunit(devs[i]));
+			continue;
+		}
 
 		/* Add the settings to our absolute/relative lists. */
 		switch (type & CPUFREQ_TYPE_MASK) {
@@ -867,8 +861,9 @@ cpufreq_dup_set(struct cpufreq_softc *sc, struct c
 static int
 cpufreq_curr_sysctl(SYSCTL_HANDLER_ARGS)
 {
+	struct cf_level level;
+	struct cf_level *levels;
 	struct cpufreq_softc *sc;
-	struct cf_level *levels;
 	int count, devcount, error, freq, i, n;
 	device_t *devs;
 
@@ -876,10 +871,10 @@ cpufreq_curr_sysctl(SYSCTL_HANDLER_ARGS)
 	sc = oidp->oid_arg1;
 	levels = sc->levels_buf;
 
-	error = CPUFREQ_GET(sc->dev, &levels[0]);
+	error = CPUFREQ_GET(sc->dev, &level);
 	if (error)
 		goto out;
-	freq = levels[0].total_set.freq;
+	freq = level.total_set.freq;
 	error = sysctl_handle_int(oidp, &freq, 0, req);
 	if (error != 0 || req->newptr == NULL)
 		goto out;
@@ -1000,8 +995,11 @@ out:
 int
 cpufreq_register(device_t dev)
 {
+	struct cf_setting set;
+	struct cf_setting *sets;
 	struct cpufreq_softc *sc;
 	device_t cf_dev, cpu_dev;
+	int error, freq, max, set_count, type;
 
 	/* Add a sysctl to get each driver's settings separately. */
 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
@@ -1009,14 +1007,34 @@ cpufreq_register(device_t dev)
 	    OID_AUTO, "freq_settings", CTLTYPE_STRING | CTLFLAG_RD, dev, 0,
 	    cpufreq_settings_sysctl, "A", "CPU frequency driver settings");
 
+	/* Get settings from the device and find current and maximum frequencies */
+	freq = max = CPUFREQ_VAL_UNKNOWN;
+	if (CPUFREQ_DRV_TYPE(dev, &type) == 0 &&
+	    (type & CPUFREQ_TYPE_MASK) == CPUFREQ_TYPE_ABSOLUTE) {
+		if (CPUFREQ_DRV_GET(dev, &set) == 0)
+			freq = set.freq;
+		set_count = MAX_SETTINGS;
+		sets = malloc(set_count * sizeof(*sets), M_TEMP, M_NOWAIT);
+		if (sets != NULL) {
+			if (CPUFREQ_DRV_SETTINGS(dev, sets, &set_count) == 0 &&
+			    set_count > 0)
+				max = sets[0].freq;
+			free(sets, M_TEMP);
+		}
+	}
+
 	/*
 	 * Add only one cpufreq device to each CPU.  Currently, all CPUs
 	 * must offer the same levels and be switched at the same time.
 	 */
 	cpu_dev = device_get_parent(dev);
-	if ((cf_dev = device_find_child(cpu_dev, "cpufreq", -1))) {
+	cf_dev = device_find_child(cpu_dev, "cpufreq", -1);
+	if (cf_dev != NULL) {
 		sc = device_get_softc(cf_dev);
-		sc->max_mhz = CPUFREQ_VAL_UNKNOWN;
+		if (sc->curr_level.total_set.freq == CPUFREQ_VAL_UNKNOWN)
+			sc->curr_level.total_set.freq = freq;
+		if (sc->max_mhz < max)
+			sc->max_mhz = max;
 		return (0);
 	}
 
@@ -1025,8 +1043,13 @@ cpufreq_register(device_t dev)
 	if (cf_dev == NULL)
 		return (ENOMEM);
 	device_quiet(cf_dev);
-
-	return (device_probe_and_attach(cf_dev));
+	error = device_probe(cf_dev);
+	if (error)
+		return (error);
+	sc = device_get_softc(cf_dev);
+	sc->curr_level.total_set.freq = freq;
+	sc->max_mhz = max;
+	return (device_attach(cf_dev));
 }
 
 int


More information about the freebsd-amd64 mailing list