Index: usr.sbin/powerd/powerd.8 diff -u usr.sbin/powerd/powerd.8.orig usr.sbin/powerd/powerd.8 --- usr.sbin/powerd/powerd.8.orig Fri Jun 17 05:01:43 2005 +++ usr.sbin/powerd/powerd.8 Tue Jun 21 03:55:55 2005 @@ -34,10 +34,12 @@ .Nm .Op Fl a Ar mode .Op Fl b Ar mode +.Op Fl c Ar ival .Op Fl i Ar percent .Op Fl n Ar mode .Op Fl p Ar ival .Op Fl r Ar percent +.Op Fl t .Op Fl v .Sh DESCRIPTION The @@ -69,6 +71,9 @@ Selects the .Ar mode to use while on battery power. +.It Fl c Ar ival +Specifies a different polling interval (in milliseconds) for cooling down. +The default is 10000 ms. .It Fl i Ar percent Specifies the CPU idle percent level when adaptive @@ -87,6 +92,10 @@ adaptive mode should consider the CPU running and increase performance. The default is 65% or lower. +.It Fl t +When the temperature is too high, the +.Nm +decrease the frequency for cooling down. .It Fl v Verbose mode. Messages about power changes will be printed to stdout and Index: usr.sbin/powerd/powerd.c diff -u -p usr.sbin/powerd/powerd.c.orig usr.sbin/powerd/powerd.c --- usr.sbin/powerd/powerd.c.orig Mon Apr 11 05:42:55 2005 +++ usr.sbin/powerd/powerd.c Tue Jun 21 05:32:58 2005 @@ -47,6 +47,7 @@ __FBSDID("$FreeBSD: src/usr.sbin/powerd/ #define DEFAULT_ACTIVE_PERCENT 65 #define DEFAULT_IDLE_PERCENT 90 #define DEFAULT_POLL_INTERVAL 500 /* Poll interval in milliseconds */ +#define DEFAULT_COOL_INTERVAL 10000 enum modes_t { MODE_MIN, @@ -83,11 +84,14 @@ static int cp_time_mib[2]; static int freq_mib[4]; static int levels_mib[4]; static int acline_mib[3]; +static int thermal_mib[5]; +static int temperature_mib[5]; /* Configuration */ static int cpu_running_mark; static int cpu_idle_mark; static int poll_ival; +static int cool_ival; static int apm_fd; static int exit_requested; @@ -219,6 +223,53 @@ acline_read() return (acline); } +static int +cooling_down(int curfreq, int *freqs, int numfreqs, int vflag) +{ + static int temperature = 0; /* in kelvin */ + static int count = 0; + int thermal_flags, curtemp, len, i = -1; + + len = sizeof(thermal_flags); + if (sysctl(thermal_mib, 5, &thermal_flags, &len, NULL, 0) || + !thermal_flags) { + temperature = 0; + count = 0; + return (0); + } + if (count > 0) { + count--; + return (1); + } + count = cool_ival / poll_ival; + len = sizeof(curtemp); + if (sysctl(temperature_mib, 5, &curtemp, &len, NULL, 0)) { + /* Switch to the lowest frequency for safety. */ + i = numfreqs - 1; + temperature = 0; + } else if (curtemp >= temperature) { + for (i = 0; i < numfreqs - 1; i++) + if (freqs[i] <= curfreq) + break; + if (i < numfreqs - 1) + i++; + temperature = curtemp; + } + if (i < 0) + return (1); /* Goes well, we don't need to do. */ + if (curfreq == freqs[i]) + return (1); /* We can nothing to do. */ + if (vflag) { + printf("temperature %d.%dC; " + "decreasing clock speed from %d MHz to %d MHz\n", + (temperature - 2732) / 10, (temperature - 2732) % 10, + curfreq, freqs[i]); + } + if (set_freq(freqs[i])) + err(1, "error setting CPU freq %d", freqs[i]); + return (1); +} + static void parse_mode(char *arg, int *mode, int ch) { @@ -244,7 +295,8 @@ usage(void) { fprintf(stderr, -"usage: powerd [-v] [-a mode] [-b mode] [-i %%] [-n mode] [-p ival] [-r %%]\n"); +"usage: powerd [-v] [-a mode] [-b mode] [-i %%] [-n mode] [-p ival] [-r %%]\n" +" [-t] [-c ival]\n"); exit(1); } @@ -253,7 +305,7 @@ main(int argc, char * argv[]) { long idle, total; int curfreq, *freqs, i, *mwatts, numfreqs; - int ch, mode_ac, mode_battery, mode_none, acline, mode, vflag; + int ch, mode_ac, mode_battery, mode_none, acline, mode, tflag, vflag; uint64_t mjoules_used; size_t len; @@ -262,11 +314,13 @@ main(int argc, char * argv[]) cpu_running_mark = DEFAULT_ACTIVE_PERCENT; cpu_idle_mark = DEFAULT_IDLE_PERCENT; poll_ival = DEFAULT_POLL_INTERVAL; + cool_ival = DEFAULT_COOL_INTERVAL; mjoules_used = 0; + tflag = 0; vflag = 0; apm_fd = -1; - while ((ch = getopt(argc, argv, "a:b:i:n:p:r:v")) != EOF) + while ((ch = getopt(argc, argv, "a:b:c:i:n:p:r:tv")) != EOF) switch (ch) { case 'a': parse_mode(optarg, &mode_ac, ch); @@ -274,6 +328,13 @@ main(int argc, char * argv[]) case 'b': parse_mode(optarg, &mode_battery, ch); break; + case 'c': + cool_ival = atoi(optarg); + if (cool_ival < 0) { + warnx("cooling interval is in units of ms"); + usage(); + } + break; case 'i': cpu_idle_mark = atoi(optarg); if (cpu_idle_mark < 0 || cpu_idle_mark > 100) { @@ -300,6 +361,9 @@ main(int argc, char * argv[]) usage(); } break; + case 't': + tflag = 1; + break; case 'v': vflag = 1; break; @@ -309,6 +373,7 @@ main(int argc, char * argv[]) /* Poll interval is in units of ms. */ poll_ival *= 1000; + cool_ival *= 1000; /* Look up various sysctl MIBs. */ len = 2; @@ -320,6 +385,16 @@ main(int argc, char * argv[]) len = 4; if (sysctlnametomib("dev.cpu.0.freq_levels", levels_mib, &len)) err(1, "lookup freq_levels"); + if (tflag) { + len = 5; + if (sysctlnametomib("hw.acpi.thermal.tz0.thermal_flags", + thermal_mib, &len)) + err(1, "lookup thermal_flags"); + len = 5; + if (sysctlnametomib("hw.acpi.thermal.tz0.temperature", + temperature_mib, &len)) + err(1, "lookup temperature"); + } /* Check if we can read the idle time and supported freqs. */ if (read_usage_times(NULL, NULL)) @@ -382,6 +457,9 @@ main(int argc, char * argv[]) mjoules_used += (mwatts[i] * (poll_ival / 1000)) / 1000; } + + if (tflag && cooling_down(curfreq, freqs, numfreqs, vflag)) + continue; /* Always switch to the lowest frequency in min mode. */ if (mode == MODE_MIN) {