Index: sys/dev/acpica/acpi_thermal.c diff -u -p sys/dev/acpica/acpi_thermal.c.orig sys/dev/acpica/acpi_thermal.c --- sys/dev/acpica/acpi_thermal.c.orig Tue Feb 22 09:40:13 2005 +++ sys/dev/acpica/acpi_thermal.c Tue Jun 28 00:56:51 2005 @@ -248,6 +248,16 @@ acpi_tz_attach(device_t dev) OID_AUTO, "_ACx", CTLFLAG_RD, &sc->tz_zone.ac, sizeof(sc->tz_zone.ac), "IK", ""); + SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), + OID_AUTO, "_TC1", CTLFLAG_RD, + &sc->tz_zone.tc1, 0, "TC1"); + SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), + OID_AUTO, "_TC2", CTLFLAG_RD, + &sc->tz_zone.tc2, 0, "TC2"); + SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), + OID_AUTO, "_TSP", CTLFLAG_RD, + &sc->tz_zone.tsp, 0, "TSP"); + /* * Create our thread; we only need one, it will service all of the * thermal zones. Register our power profile event handler. Index: usr.sbin/powerd/Makefile diff -u usr.sbin/powerd/Makefile.orig usr.sbin/powerd/Makefile --- usr.sbin/powerd/Makefile.orig Sun Feb 27 07:50:25 2005 +++ usr.sbin/powerd/Makefile Mon Jun 27 21:36:19 2005 @@ -2,6 +2,7 @@ PROG= powerd MAN= powerd.8 +SRCS= powerd.c cooling.c WARNS?= 6 .include Index: usr.sbin/powerd/cooling.c diff -u -p /dev/null usr.sbin/powerd/cooling.c --- /dev/null Tue Jun 28 14:00:00 2005 +++ usr.sbin/powerd/cooling.c Tue Jun 28 01:03:33 2005 @@ -0,0 +1,133 @@ +/*- + * Copyright (c) 2005 Hajimu UMEMOTO + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#include "cooling.h" + +struct cool_parm * +cool_init(int *freqs, int numfreqs, int poll_ival) +{ + struct cool_parm *cp; + size_t len; + int r; + + if ((cp = malloc(sizeof(*cp))) == NULL) { + warn("malloc"); + return (NULL); + } + len = sizeof(cp->psv); + r = sysctlbyname("hw.acpi.thermal.tz0._PSV", &cp->psv, &len, NULL, 0); + if (r || cp->psv < 0) { + warnx("lookup _PSV"); + goto err; + } + len = sizeof(cp->tc1); + r = sysctlbyname("hw.acpi.thermal.tz0._TC1", &cp->tc1, &len, NULL, 0); + if (r || cp->tc1 < 0) { + warnx("lookup _TC1"); + goto err; + } + len = sizeof(cp->tc2); + r = sysctlbyname("hw.acpi.thermal.tz0._TC2", &cp->tc2, &len, NULL, 0); + if (r || cp->tc2 < 0) { + warnx("lookup _TC2"); + goto err; + } + len = sizeof(cp->tsp); + r = sysctlbyname("hw.acpi.thermal.tz0._TSP", &cp->tsp, &len, NULL, 0); + if (r || cp->tsp < 0) { + warnx("lookup _TSP"); + goto err; + } + len = 5; + if (sysctlnametomib("hw.acpi.thermal.tz0.temperature", cp->temp_mib, + &len)) { + warn("lookup temperature"); + goto err; + } + cp->freqs = freqs; + cp->numfreqs = numfreqs; + cp->ival = cp->tsp * 100000 / poll_ival; + cp->count = 0; + cp->temp = 0; + return (cp); + +err: + free(cp); + return (NULL); + +} + +cool_state_t +cool_down(struct cool_parm *cp, int curfreq, int *newfreq) +{ + int curtemp, len, perf, p, i; + + if (cp == NULL) + return (CS_NORMAL); + + if (cp->count > 0) { + cp->count--; + return ((cp->temp >= cp->psv) ? CS_COOLING : CS_NORMAL); + } + cp->count = cp->ival; + + len = sizeof(curtemp); + if (sysctl(cp->temp_mib, 5, &curtemp, &len, NULL, 0)) + err(1, "lookup temperature"); + if (curtemp < cp->psv) { + cp->temp = curtemp; + return (CS_NORMAL); + } + + p = cp->tc1 * (curtemp - cp->temp) + cp->tc2 * (curtemp - cp->psv); + p /= 10; + cp->temp = curtemp; + if (p == 0) + return (CS_COOLING); + perf = 100 * curfreq / cp->freqs[0] - p; + if (perf < 0) + perf = 0; + else if (perf > 100) + perf = 100; + + for (i = 0; i < cp->numfreqs - 1; i++) + if (cp->freqs[i] <= curfreq * perf / 100) + break; + if (curfreq == cp->freqs[i]) + return (CS_COOLING); + + *newfreq = cp->freqs[i]; + return (CS_NEWFREQ); +} Index: usr.sbin/powerd/cooling.h diff -u /dev/null usr.sbin/powerd/cooling.h --- /dev/null Tue Jun 28 14:00:00 2005 +++ usr.sbin/powerd/cooling.h Tue Jun 28 00:36:45 2005 @@ -0,0 +1,54 @@ +/*- + * Copyright (c) 2005 Hajimu UMEMOTO + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef COOLING_H +#define COOLING_H + +typedef enum { + CS_NORMAL = 0, + CS_COOLING = 1, + CS_NEWFREQ = 2 +} cool_state_t; + +struct cool_parm { + int temp_mib[5]; + int psv; + int tc1; + int tc2; + int tsp; + int *freqs; + int numfreqs; + int ival; + int count; + int temp; /* in kelvin x 10 */ +}; + +extern struct cool_parm *cool_init(int *, int, int); +extern cool_state_t cool_down(struct cool_parm *, int, int *); + +#endif /* !COOLING_H */ 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 Mon Jun 27 19:30:50 2005 @@ -38,6 +38,7 @@ .Op Fl n Ar mode .Op Fl p Ar ival .Op Fl r Ar percent +.Op Fl t .Op Fl v .Sh DESCRIPTION The @@ -87,6 +88,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 28 14:05:44 2005 @@ -44,6 +44,8 @@ __FBSDID("$FreeBSD: src/usr.sbin/powerd/ #include #include +#include "cooling.h" + #define DEFAULT_ACTIVE_PERCENT 65 #define DEFAULT_IDLE_PERCENT 90 #define DEFAULT_POLL_INTERVAL 500 /* Poll interval in milliseconds */ @@ -244,16 +246,17 @@ usage(void) { fprintf(stderr, -"usage: powerd [-v] [-a mode] [-b mode] [-i %%] [-n mode] [-p ival] [-r %%]\n"); +"usage: powerd [-t] [-v] [-a mode] [-b mode] [-i %%] [-n mode] [-p ival] [-r %%]\n"); exit(1); } int main(int argc, char * argv[]) { + struct cool_parm *cooling_parm = NULL; long idle, total; - int curfreq, *freqs, i, *mwatts, numfreqs; - int ch, mode_ac, mode_battery, mode_none, acline, mode, vflag; + int curfreq, *freqs, i, *mwatts, numfreqs, newfreq; + int ch, mode_ac, mode_battery, mode_none, acline, mode, tflag, vflag; uint64_t mjoules_used; size_t len; @@ -263,10 +266,11 @@ main(int argc, char * argv[]) cpu_idle_mark = DEFAULT_IDLE_PERCENT; poll_ival = DEFAULT_POLL_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:i:n:p:r:tv")) != EOF) switch (ch) { case 'a': parse_mode(optarg, &mode_ac, ch); @@ -300,6 +304,9 @@ main(int argc, char * argv[]) usage(); } break; + case 't': + tflag = 1; + break; case 'v': vflag = 1; break; @@ -330,6 +337,11 @@ main(int argc, char * argv[]) /* Decide whether to use ACPI or APM to read the AC line status. */ acline_init(); + /* Initialize passive cooling. */ + if (tflag && + (cooling_parm = cool_init(freqs, numfreqs, poll_ival)) == NULL) + warnx("passive cooling is disabled"); + /* Run in the background unless in verbose mode. */ if (!vflag) daemon(0, 0); @@ -383,6 +395,25 @@ main(int argc, char * argv[]) (mwatts[i] * (poll_ival / 1000)) / 1000; } + /* Cool down by decreasing clock speed. */ + switch (cool_down(cooling_parm, curfreq, &newfreq)) { + case CS_NEWFREQ: + if (vflag) { + printf("temperature %d.%dC; decreasing clock " + "speed from %d MHz to %d MHz\n", + (cooling_parm->temp - 2732) / 10, + (cooling_parm->temp - 2732) % 10, + curfreq, newfreq); + } + if (set_freq(newfreq)) + err(1, "error setting CPU freq %d", newfreq); + continue; + case CS_COOLING: + continue; + default: + break; + } + /* Always switch to the lowest frequency in min mode. */ if (mode == MODE_MIN) { if (curfreq != freqs[numfreqs - 1]) { @@ -451,6 +482,7 @@ main(int argc, char * argv[]) } free(freqs); free(mwatts); + free(cooling_parm); exit(0); }