From owner-svn-src-head@FreeBSD.ORG Sun Feb 21 22:13:58 2010 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 6246A106566C; Sun, 21 Feb 2010 22:13:58 +0000 (UTC) (envelope-from nwhitehorn@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 4FACC8FC12; Sun, 21 Feb 2010 22:13:58 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o1LMDw0j053387; Sun, 21 Feb 2010 22:13:58 GMT (envelope-from nwhitehorn@svn.freebsd.org) Received: (from nwhitehorn@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o1LMDwtj053385; Sun, 21 Feb 2010 22:13:58 GMT (envelope-from nwhitehorn@svn.freebsd.org) Message-Id: <201002212213.o1LMDwtj053385@svn.freebsd.org> From: Nathan Whitehorn Date: Sun, 21 Feb 2010 22:13:58 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r204180 - head/sys/powerpc/powermac X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 21 Feb 2010 22:13:58 -0000 Author: nwhitehorn Date: Sun Feb 21 22:13:57 2010 New Revision: 204180 URL: http://svn.freebsd.org/changeset/base/204180 Log: Add a simple fan management callout to the SMU driver. This is designed such that a fancier thermal management algorithm can be run from user space, but the kernel will at least ensure your machine does not either sound like a wind tunnel or catch fire. Modified: head/sys/powerpc/powermac/smu.c Modified: head/sys/powerpc/powermac/smu.c ============================================================================== --- head/sys/powerpc/powermac/smu.c Sun Feb 21 21:03:37 2010 (r204179) +++ head/sys/powerpc/powermac/smu.c Sun Feb 21 22:13:57 2010 (r204180) @@ -32,10 +32,12 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include #include +#include #include #include @@ -58,7 +60,9 @@ struct smu_fan { cell_t max_rpm; cell_t unmanaged_rpm; char location[32]; + int old_style; + int setpoint; }; struct smu_sensor { @@ -92,6 +96,9 @@ struct smu_softc { struct smu_sensor *sc_sensors; int sc_nsensors; + struct callout sc_fanmgt_callout; + time_t sc_lastuserchange; + /* Calibration data */ uint16_t sc_cpu_diode_scale; int16_t sc_cpu_diode_offset; @@ -103,6 +110,10 @@ struct smu_softc { uint16_t sc_slots_pow_scale; int16_t sc_slots_pow_offset; + + /* Thermal management parameters */ + int sc_target_temp; /* Default 55 C */ + int sc_critical_temp; /* Default 90 C */ }; /* regular bus attachment functions */ @@ -121,6 +132,7 @@ static int smu_get_datablock(device_t de size_t len); static void smu_attach_fans(device_t dev, phandle_t fanroot); static void smu_attach_sensors(device_t dev, phandle_t sensroot); +static void smu_fanmgt_callout(void *xdev); /* where to find the doorbell GPIO */ @@ -145,6 +157,7 @@ DRIVER_MODULE(smu, nexus, smu_driver, sm MALLOC_DEFINE(M_SMU, "smu", "SMU Sensor Information"); #define SMU_MAILBOX 0x8000860c +#define SMU_FANMGT_INTERVAL 500 /* ms */ /* Command types */ #define SMU_ADC 0xd8 @@ -261,6 +274,24 @@ smu_attach(device_t dev) sc->sc_slots_pow_scale = (data[4] << 8) + data[5]; sc->sc_slots_pow_offset = (data[6] << 8) + data[7]; + /* + * Set up simple-minded thermal management. + */ + sc->sc_target_temp = 55; + sc->sc_critical_temp = 90; + + SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, + "target_temp", CTLTYPE_INT | CTLFLAG_RW, &sc->sc_target_temp, + sizeof(int), "Target temperature (C)"); + SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, + "critical_temp", CTLTYPE_INT | CTLFLAG_RW, + &sc->sc_critical_temp, sizeof(int), "Critical temperature (C)"); + + callout_init(&sc->sc_fanmgt_callout, 1); + smu_fanmgt_callout(dev); + return (0); } @@ -470,6 +501,9 @@ smu_fan_set_rpm(device_t smu, struct smu error = smu_run_cmd(smu, &cmd); } + if (error == 0) + fan->setpoint = rpm; + return (error); } @@ -505,6 +539,7 @@ smu_fanrpm_sysctl(SYSCTL_HANDLER_ARGS) if (error || !req->newptr) return (error); + sc->sc_lastuserchange = time_uptime; return (smu_fan_set_rpm(smu, fan, rpm)); } @@ -556,12 +591,11 @@ smu_attach_fans(device_t dev, phandle_t sizeof(cell_t)) != sizeof(cell_t)) fan->unmanaged_rpm = fan->max_rpm; + fan->setpoint = smu_fan_read_rpm(dev, fan); + OF_getprop(child, "location", fan->location, sizeof(fan->location)); - - /* Make sure it is at a safe value initially */ - //smu_fan_set_rpm(dev, fan, fan->unmanaged_rpm); - + /* Add sysctls */ for (i = 0; i < strlen(fan->location); i++) { sysctl_name[i] = tolower(fan->location[i]); @@ -745,3 +779,77 @@ smu_attach_sensors(device_t dev, phandle } } +static int +ms_to_ticks(int ms) +{ + if (hz > 1000) + return ms*(hz/1000); + + return ms/(1000/hz); +} + +static void +smu_fanmgt_callout(void *xdev) { + device_t smu = xdev; + struct smu_softc *sc; + int i, maxtemp, temp, factor; + + sc = device_get_softc(smu); + + if (time_uptime - sc->sc_lastuserchange < 3) { + /* + * If we have heard from a user process in the last 3 seconds, + * go away. + */ + + callout_reset(&sc->sc_fanmgt_callout, + ms_to_ticks(SMU_FANMGT_INTERVAL), smu_fanmgt_callout, smu); + return; + } + + maxtemp = 0; + for (i = 0; i < sc->sc_nsensors; i++) { + if (sc->sc_sensors[i].type != SMU_TEMP_SENSOR) + continue; + + temp = smu_sensor_read(smu, &sc->sc_sensors[i]); + if (temp > maxtemp) + maxtemp = temp; + } + + if (maxtemp < 10) { /* Bail if no good sensors */ + for (i = 0; i < sc->sc_nfans; i++) + smu_fan_set_rpm(smu, &sc->sc_fans[i], + sc->sc_fans[i].unmanaged_rpm); + return; + } + + if (maxtemp > sc->sc_critical_temp) { + device_printf(smu, "WARNING: Current system temperature (%d C) " + "exceeds critical temperature (%d C)! Shutting down!\n", + maxtemp, sc->sc_critical_temp); + shutdown_nice(RB_POWEROFF); + } + + if (maxtemp - sc->sc_target_temp > 20) + device_printf(smu, "WARNING: Current system temperature (%d C) " + "more than 20 degrees over target temperature (%d C)!\n", + maxtemp, sc->sc_target_temp); + + if (maxtemp > sc->sc_target_temp) + factor = 110; + else if (sc->sc_target_temp - maxtemp > 4) + factor = 90; + else if (sc->sc_target_temp - maxtemp > 1) + factor = 95; + else + factor = 100; + + for (i = 0; i < sc->sc_nfans; i++) + smu_fan_set_rpm(smu, &sc->sc_fans[i], + (sc->sc_fans[i].setpoint * factor) / 100); + + callout_reset(&sc->sc_fanmgt_callout, + ms_to_ticks(SMU_FANMGT_INTERVAL), smu_fanmgt_callout, smu); +} +