My recent powerd problem

Aragon Gouveia aragon at phat.za.net
Sun Nov 11 11:46:55 PST 2007


Hi,

I recently installed FreeBSD 7.0-BETA2 onto my new HP Pavilion dv2600
notebook.  I've encountered a couple of hiccups with it and this is my
report of one of them...

For some reason powerd would not lower the CPU frequency of my 2.2 GHz Core
2 Duo when it was in adaptive mode.  When I ran it with -v I noticed it'd
endlessly try set the CPU frequency to 2200 when the machine idled.  Here's
why:

dev.cpu.0.freq_levels: 2201/35000 2200/35000 1925/30625 1650/26250
1600/23000 1400/20125 1200/16000 1050/14000 900/12000 800/14000 700/12250
600/10500 500/8750 400/7000 300/5250 200/3500 100/1750

# sysctl -w dev.cpu.0.freq=2200
dev.cpu.0.freq: 2201 -> 2201

So when trying to set the frequency to 2200 it gets changed back to 2201. 
Powerd would endlessly try set 2200 but it'd stay at 2201.

So I wrote a patch to powerd to detect this and remove a frequency if it was
unable to set it.  It is attached to this mail.

Well the patch works great and powerd is functioning normally now.  However,
I'm not sure this is the best fix.  I'd really like to know why
dev.cpu.0.freq_levels has 2201 and 2200 listed, and more importantly why
2200 can't be set despite its listing.  Could this be a problem with my
ACPI?  Would an AML mod fix it?


Thanks,
Aragon
-------------- next part --------------
--- powerd.c.orig	2007-06-13 21:05:11.000000000 +0200
+++ powerd.c	2007-11-10 23:59:09.000000000 +0200
@@ -79,6 +79,7 @@
 
 static int	read_usage_times(long *idle, long *total);
 static int	read_freqs(int *numfreqs, int **freqs, int **power);
+static void	rm_freq(int *numfreqs, int rmfreq, int **freqs, int **power);
 static int	set_freq(int freq);
 static void	acline_init(void);
 static void	acline_read(void);
@@ -189,6 +190,41 @@
 	return (0);
 }
 
+static void
+rm_freq(int *numfreqs, int rmfreq, int **freqs, int **power)
+{
+	int i, j=0, newfreqs[(*numfreqs)-1], newpower[(*numfreqs)-1];
+
+	if (*numfreqs < 2) {
+		// nothing more we can do
+		free(*freqs);
+		free(*power);
+		errx(1, "No more CPU frequencies to set");
+	}
+
+	for (i=0; i<*numfreqs; i++) {
+		if (i == rmfreq) continue;
+		newfreqs[j] = (*freqs)[i];
+		newpower[j] = (*power)[i];
+		j++;
+	}
+
+	free(*freqs);
+	free(*power);
+	(*numfreqs)--;
+	if ((*freqs = malloc(*numfreqs * sizeof(int))) == NULL)
+		err(1, "error removing CPU frequency");
+	if ((*power = malloc(*numfreqs * sizeof(int))) == NULL) {
+		free(*freqs);
+		err(1, "error removing CPU frequency");
+	}
+		
+	for (i=0; i<=j; i++) {
+		(*freqs)[i] = newfreqs[i];
+		(*power)[i] = newpower[i];
+	}
+}
+
 static int
 set_freq(int freq)
 {
@@ -555,6 +591,13 @@
 					    freqs[numfreqs - 1]);
 					continue;
 				}
+				if (sysctl(freq_mib, 4, &curfreq, &len, NULL, 0) == 0) {
+					if (curfreq != freqs[numfreqs-1]) {
+						if (vflag)
+							printf("error setting CPU frequency %d, removing from list\n", freqs[numfreqs-1]);
+						rm_freq(&numfreqs, numfreqs-1, &freqs, &mwatts);
+					}
+				}
 			}
 			continue;
 		}
@@ -573,6 +616,13 @@
 				    	    freqs[0]);
 					continue;
 				}
+				if (sysctl(freq_mib, 4, &curfreq, &len, NULL, 0) == 0) {
+					if (curfreq != freqs[0]) {
+						if (vflag)
+							printf("error setting CPU frequency %d, removing from list\n", freqs[0]);
+						rm_freq(&numfreqs, 0, &freqs, &mwatts);
+					}
+				}
 			}
 			continue;
 		}
@@ -605,6 +655,15 @@
 			if (set_freq(freqs[i]))
 				warn("error setting CPU frequency %d",
 				    freqs[i]);
+			// Check if it actually got set
+			len = sizeof(curfreq);
+			if (sysctl(freq_mib, 4, &curfreq, &len, NULL, 0) == 0) {
+				if (curfreq != freqs[i]) {
+					if (vflag)
+						printf("error setting CPU frequency %d, removing from list\n", freqs[i]);
+					rm_freq(&numfreqs, i, &freqs, &mwatts);
+				}
+			}
 		} else if (idle > (total * cpu_idle_mark) / 100 &&
 		    curfreq > freqs[numfreqs - 1]) {
 			i++;
@@ -616,6 +675,15 @@
 			if (set_freq(freqs[i]) != 0)
 				warn("error setting CPU frequency %d",
 				    freqs[i]);
+			// Check if it actually got set
+			len = sizeof(curfreq);
+			if (sysctl(freq_mib, 4, &curfreq, &len, NULL, 0) == 0) {
+				if (curfreq != freqs[i]) {
+					if (vflag)
+						printf("error setting CPU frequency %d, removing from list\n", freqs[i]);
+					rm_freq(&numfreqs, i, &freqs, &mwatts);
+				}
+			}
 		}
 	}
 	free(freqs);


More information about the freebsd-acpi mailing list