acpi_thermal.c revision 149482
167761Smsmith/*- 278915Smsmith * Copyright (c) 2000, 2001 Michael Smith 367761Smsmith * Copyright (c) 2000 BSDi 467761Smsmith * All rights reserved. 567761Smsmith * 667761Smsmith * Redistribution and use in source and binary forms, with or without 767761Smsmith * modification, are permitted provided that the following conditions 867761Smsmith * are met: 967761Smsmith * 1. Redistributions of source code must retain the above copyright 1067761Smsmith * notice, this list of conditions and the following disclaimer. 1167761Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1267761Smsmith * notice, this list of conditions and the following disclaimer in the 1367761Smsmith * documentation and/or other materials provided with the distribution. 1467761Smsmith * 1567761Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1667761Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1767761Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1867761Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1967761Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2067761Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2167761Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2267761Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2367761Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2467761Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2567761Smsmith * SUCH DAMAGE. 2667761Smsmith */ 2767761Smsmith 28119418Sobrien#include <sys/cdefs.h> 29119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/acpica/acpi_thermal.c 149482 2005-08-26 02:21:02Z kan $"); 30119418Sobrien 3167761Smsmith#include "opt_acpi.h" 3267761Smsmith#include <sys/param.h> 3367761Smsmith#include <sys/kernel.h> 34133624Snjl#include <sys/bus.h> 35148138Sume#include <sys/cpu.h> 3691126Smsmith#include <sys/kthread.h> 37133624Snjl#include <sys/malloc.h> 38129879Sphk#include <sys/module.h> 3967761Smsmith#include <sys/bus.h> 4091126Smsmith#include <sys/proc.h> 41128991Snjl#include <sys/reboot.h> 4279283Smsmith#include <sys/sysctl.h> 4391126Smsmith#include <sys/unistd.h> 4491640Siwasaki#include <sys/power.h> 4567761Smsmith 46148138Sume#include "cpufreq_if.h" 47148138Sume 4867761Smsmith#include "acpi.h" 4967761Smsmith#include <dev/acpica/acpivar.h> 5067761Smsmith 51119529Snjl/* Hooks for the ACPI CA debugging infrastructure */ 5278999Smsmith#define _COMPONENT ACPI_THERMAL 5391126SmsmithACPI_MODULE_NAME("THERMAL") 5469744Smsmith 5571874Smsmith#define TZ_ZEROC 2732 5671874Smsmith#define TZ_KELVTOC(x) (((x) - TZ_ZEROC) / 10), (((x) - TZ_ZEROC) % 10) 5767761Smsmith 58125366Snjl#define TZ_NOTIFY_TEMPERATURE 0x80 /* Temperature changed. */ 59125366Snjl#define TZ_NOTIFY_LEVELS 0x81 /* Cooling levels changed. */ 60125366Snjl#define TZ_NOTIFY_DEVICES 0x82 /* Device lists changed. */ 61125366Snjl#define TZ_NOTIFY_CRITICAL 0xcc /* Fake notify that _CRT/_HOT reached. */ 6278915Smsmith 63125335Snjl/* Check for temperature changes every 10 seconds by default */ 64125335Snjl#define TZ_POLLRATE 10 6578915Smsmith 66125335Snjl/* Make sure the reported temperature is valid for this number of polls. */ 67125335Snjl#define TZ_VALIDCHECKS 3 68125335Snjl 69125366Snjl/* Notify the user we will be shutting down in one more poll cycle. */ 70125366Snjl#define TZ_NOTIFYCOUNT (TZ_VALIDCHECKS - 1) 71125366Snjl 72119529Snjl/* ACPI spec defines this */ 73119529Snjl#define TZ_NUMLEVELS 10 7479375Smsmithstruct acpi_tz_zone { 7578915Smsmith int ac[TZ_NUMLEVELS]; 7678915Smsmith ACPI_BUFFER al[TZ_NUMLEVELS]; 7778915Smsmith int crt; 7878915Smsmith int hot; 7978915Smsmith ACPI_BUFFER psl; 8078915Smsmith int psv; 8178915Smsmith int tc1; 8278915Smsmith int tc2; 8378915Smsmith int tsp; 8478915Smsmith int tzp; 8578915Smsmith}; 8678915Smsmith 8767761Smsmithstruct acpi_tz_softc { 88119529Snjl device_t tz_dev; 89119529Snjl ACPI_HANDLE tz_handle; /*Thermal zone handle*/ 90119529Snjl int tz_temperature; /*Current temperature*/ 91119529Snjl int tz_active; /*Current active cooling*/ 9279375Smsmith#define TZ_ACTIVE_NONE -1 93119529Snjl int tz_requested; /*Minimum active cooling*/ 94119529Snjl int tz_thflags; /*Current temp-related flags*/ 9579375Smsmith#define TZ_THFLAG_NONE 0 9679375Smsmith#define TZ_THFLAG_PSV (1<<0) 9779375Smsmith#define TZ_THFLAG_HOT (1<<2) 98148138Sume#define TZ_THFLAG_CRT (1<<3) 9979283Smsmith int tz_flags; 100119529Snjl#define TZ_FLAG_NO_SCP (1<<0) /*No _SCP method*/ 101119529Snjl#define TZ_FLAG_GETPROFILE (1<<1) /*Get power_profile in timeout*/ 102133624Snjl#define TZ_FLAG_GETSETTINGS (1<<2) /*Get devs/setpoints*/ 103119529Snjl struct timespec tz_cooling_started; 104119529Snjl /*Current cooling starting time*/ 10579283Smsmith 106119529Snjl struct sysctl_ctx_list tz_sysctl_ctx; 10779283Smsmith struct sysctl_oid *tz_sysctl_tree; 108133624Snjl eventhandler_tag tz_event; 109133624Snjl 110119529Snjl struct acpi_tz_zone tz_zone; /*Thermal zone parameters*/ 111125335Snjl int tz_validchecks; 112148138Sume 113148138Sume /* passive cooling */ 114148138Sume struct proc *tz_cooling_proc; 115148703Sume int tz_cooling_proc_running; 116148138Sume int tz_cooling_enabled; 117148138Sume int tz_cooling_active; 118148138Sume int tz_cooling_updated; 119149201Sume int tz_cooling_saved_freq; 12067761Smsmith}; 12167761Smsmith 122148138Sume#define CPUFREQ_MAX_LEVELS 64 /* XXX cpufreq should export this */ 123148138Sume 12467761Smsmithstatic int acpi_tz_probe(device_t dev); 12567761Smsmithstatic int acpi_tz_attach(device_t dev); 12678915Smsmithstatic int acpi_tz_establish(struct acpi_tz_softc *sc); 127119529Snjlstatic void acpi_tz_monitor(void *Context); 12878915Smsmithstatic void acpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg); 12978915Smsmithstatic void acpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg); 130119529Snjlstatic void acpi_tz_getparam(struct acpi_tz_softc *sc, char *node, 131119529Snjl int *data); 13279283Smsmithstatic void acpi_tz_sanity(struct acpi_tz_softc *sc, int *val, char *what); 13379375Smsmithstatic int acpi_tz_active_sysctl(SYSCTL_HANDLER_ARGS); 134148138Sumestatic int acpi_tz_cooling_sysctl(SYSCTL_HANDLER_ARGS); 135119529Snjlstatic void acpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, 136119529Snjl void *context); 137133624Snjlstatic void acpi_tz_signal(struct acpi_tz_softc *sc, int flags); 138133624Snjlstatic void acpi_tz_timeout(struct acpi_tz_softc *sc, int flags); 13991640Siwasakistatic void acpi_tz_power_profile(void *arg); 14091126Smsmithstatic void acpi_tz_thread(void *arg); 141148138Sumestatic int acpi_tz_cooling_is_available(struct acpi_tz_softc *sc); 142148138Sumestatic int acpi_tz_cooling_thread_start(struct acpi_tz_softc *sc); 14391126Smsmith 14467761Smsmithstatic device_method_t acpi_tz_methods[] = { 14567761Smsmith /* Device interface */ 14667761Smsmith DEVMETHOD(device_probe, acpi_tz_probe), 14767761Smsmith DEVMETHOD(device_attach, acpi_tz_attach), 14867761Smsmith 14967761Smsmith {0, 0} 15067761Smsmith}; 15167761Smsmith 15267761Smsmithstatic driver_t acpi_tz_driver = { 15367761Smsmith "acpi_tz", 15467761Smsmith acpi_tz_methods, 15567761Smsmith sizeof(struct acpi_tz_softc), 15667761Smsmith}; 15767761Smsmith 15889054Smsmithstatic devclass_t acpi_tz_devclass; 15967761SmsmithDRIVER_MODULE(acpi_tz, acpi, acpi_tz_driver, acpi_tz_devclass, 0, 0); 160128071SnjlMODULE_DEPEND(acpi_tz, acpi, 1, 1, 1); 16167761Smsmith 16279283Smsmithstatic struct sysctl_ctx_list acpi_tz_sysctl_ctx; 16379283Smsmithstatic struct sysctl_oid *acpi_tz_sysctl_tree; 16479283Smsmith 165119529Snjl/* Minimum cooling run time */ 166119529Snjlstatic int acpi_tz_min_runtime = 0; 16788420Siwasakistatic int acpi_tz_polling_rate = TZ_POLLRATE; 16885699Siwasaki 169119529Snjl/* Timezone polling thread */ 170119529Snjlstatic struct proc *acpi_tz_proc; 171133624SnjlACPI_LOCK_DECL(thermal, "ACPI thermal zone"); 172119529Snjl 17367761Smsmithstatic int 17467761Smsmithacpi_tz_probe(device_t dev) 17567761Smsmith{ 17678999Smsmith int result; 177148138Sume 178119529Snjl if (acpi_get_type(dev) == ACPI_TYPE_THERMAL && !acpi_disabled("thermal")) { 179120453Snjl device_set_desc(dev, "Thermal Zone"); 18078999Smsmith result = -10; 181133624Snjl } else 18278999Smsmith result = ENXIO; 183119529Snjl return (result); 18467761Smsmith} 18567761Smsmith 18667761Smsmithstatic int 18767761Smsmithacpi_tz_attach(device_t dev) 18867761Smsmith{ 18967761Smsmith struct acpi_tz_softc *sc; 19079283Smsmith struct acpi_softc *acpi_sc; 19178915Smsmith int error; 19279283Smsmith char oidname[8]; 19367761Smsmith 19496926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 19569744Smsmith 19667761Smsmith sc = device_get_softc(dev); 19767761Smsmith sc->tz_dev = dev; 19867761Smsmith sc->tz_handle = acpi_get_handle(dev); 19979375Smsmith sc->tz_requested = TZ_ACTIVE_NONE; 200135548Snjl sc->tz_active = TZ_ACTIVE_NONE; 201135548Snjl sc->tz_thflags = TZ_THFLAG_NONE; 202148138Sume sc->tz_cooling_proc = NULL; 203148703Sume sc->tz_cooling_proc_running = FALSE; 204148138Sume sc->tz_cooling_active = FALSE; 205148138Sume sc->tz_cooling_updated = FALSE; 20667761Smsmith 20778915Smsmith /* 208148138Sume * Always attempt to enable passive cooling for tz0. Users can enable 209148138Sume * it for other zones manually for now. 210148138Sume * 211148138Sume * XXX We need to test if multiple zones conflict with each other 212148138Sume * since cpufreq currently sets all CPUs to the given frequency whereas 213148138Sume * it's possible for different thermal zones to specify independent 214148138Sume * settings for multiple CPUs. 215148138Sume */ 216148138Sume sc->tz_cooling_enabled = (device_get_unit(dev) == 0); 217148138Sume 218148138Sume /* 21978915Smsmith * Parse the current state of the thermal zone and build control 220133624Snjl * structures. We don't need to worry about interference with the 221133624Snjl * control thread since we haven't fully attached this device yet. 22278915Smsmith */ 22378915Smsmith if ((error = acpi_tz_establish(sc)) != 0) 224133624Snjl return (error); 225133624Snjl 22678915Smsmith /* 22778915Smsmith * Register for any Notify events sent to this zone. 22878915Smsmith */ 229148138Sume AcpiInstallNotifyHandler(sc->tz_handle, ACPI_DEVICE_NOTIFY, 23078999Smsmith acpi_tz_notify_handler, sc); 23170271Stakawata 23271874Smsmith /* 23379283Smsmith * Create our sysctl nodes. 23479283Smsmith * 23579283Smsmith * XXX we need a mechanism for adding nodes under ACPI. 23679283Smsmith */ 23779283Smsmith if (device_get_unit(dev) == 0) { 23879283Smsmith acpi_sc = acpi_device_get_parent_softc(dev); 23979283Smsmith sysctl_ctx_init(&acpi_tz_sysctl_ctx); 24079283Smsmith acpi_tz_sysctl_tree = SYSCTL_ADD_NODE(&acpi_tz_sysctl_ctx, 241119529Snjl SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), 242119529Snjl OID_AUTO, "thermal", CTLFLAG_RD, 0, ""); 24385699Siwasaki SYSCTL_ADD_INT(&acpi_tz_sysctl_ctx, 24485699Siwasaki SYSCTL_CHILDREN(acpi_tz_sysctl_tree), 24585699Siwasaki OID_AUTO, "min_runtime", CTLFLAG_RD | CTLFLAG_RW, 246119529Snjl &acpi_tz_min_runtime, 0, 247119529Snjl "minimum cooling run time in sec"); 24888420Siwasaki SYSCTL_ADD_INT(&acpi_tz_sysctl_ctx, 24988420Siwasaki SYSCTL_CHILDREN(acpi_tz_sysctl_tree), 25088420Siwasaki OID_AUTO, "polling_rate", CTLFLAG_RD | CTLFLAG_RW, 25188420Siwasaki &acpi_tz_polling_rate, 0, "monitor polling rate"); 25279283Smsmith } 25379283Smsmith sysctl_ctx_init(&sc->tz_sysctl_ctx); 25479283Smsmith sprintf(oidname, "tz%d", device_get_unit(dev)); 25579283Smsmith sc->tz_sysctl_tree = SYSCTL_ADD_NODE(&sc->tz_sysctl_ctx, 256119529Snjl SYSCTL_CHILDREN(acpi_tz_sysctl_tree), 257119529Snjl OID_AUTO, oidname, CTLFLAG_RD, 0, ""); 258134541Speter SYSCTL_ADD_OPAQUE(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 259134541Speter OID_AUTO, "temperature", CTLFLAG_RD, &sc->tz_temperature, 260134961Snjl sizeof(sc->tz_temperature), "IK", 261134961Snjl "current thermal zone temperature"); 26279375Smsmith SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 26379375Smsmith OID_AUTO, "active", CTLTYPE_INT | CTLFLAG_RW, 26479375Smsmith sc, 0, acpi_tz_active_sysctl, "I", ""); 265148138Sume SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 266148138Sume OID_AUTO, "passive_cooling", CTLTYPE_INT | CTLFLAG_RW, 267148138Sume sc, 0, acpi_tz_cooling_sysctl, "I", ""); 268148138Sume 26979283Smsmith SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 27079375Smsmith OID_AUTO, "thermal_flags", CTLFLAG_RD, 27179375Smsmith &sc->tz_thflags, 0, "thermal zone flags"); 27286399Siwasaki SYSCTL_ADD_OPAQUE(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 273134961Snjl OID_AUTO, "_PSV", CTLFLAG_RD, &sc->tz_zone.psv, 274134961Snjl sizeof(sc->tz_zone.psv), "IK", ""); 275134961Snjl SYSCTL_ADD_OPAQUE(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 276134541Speter OID_AUTO, "_HOT", CTLFLAG_RD, &sc->tz_zone.hot, 277134541Speter sizeof(sc->tz_zone.hot), "IK", ""); 278134541Speter SYSCTL_ADD_OPAQUE(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 279134541Speter OID_AUTO, "_CRT", CTLFLAG_RD, &sc->tz_zone.crt, 280134541Speter sizeof(sc->tz_zone.crt), "IK", ""); 281134541Speter SYSCTL_ADD_OPAQUE(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 28286399Siwasaki OID_AUTO, "_ACx", CTLFLAG_RD, &sc->tz_zone.ac, 283134541Speter sizeof(sc->tz_zone.ac), "IK", ""); 28479283Smsmith 28579283Smsmith /* 286148138Sume * Create thread to service all of the thermal zones. Register 287148138Sume * our power profile event handler. 28879375Smsmith */ 289133624Snjl sc->tz_event = EVENTHANDLER_REGISTER(power_profile_change, 290133624Snjl acpi_tz_power_profile, sc, 0); 291133624Snjl if (acpi_tz_proc == NULL) { 292133624Snjl error = kthread_create(acpi_tz_thread, NULL, &acpi_tz_proc, 293133624Snjl RFHIGHPID, 0, "acpi_thermal"); 294133624Snjl if (error != 0) { 295133624Snjl device_printf(sc->tz_dev, "could not create thread - %d", error); 296133624Snjl goto out; 297133624Snjl } 298133624Snjl } 29979375Smsmith 300148138Sume /* Create a thread to handle passive cooling for each zone if enabled. */ 301148138Sume if (sc->tz_cooling_enabled) { 302148138Sume if (acpi_tz_cooling_is_available(sc)) { 303148138Sume error = acpi_tz_cooling_thread_start(sc); 304148138Sume if (error != 0) { 305148138Sume sc->tz_cooling_enabled = FALSE; 306148138Sume goto out; 307148138Sume } 308148138Sume } else 309148138Sume sc->tz_cooling_enabled = FALSE; 310148138Sume } 311148138Sume 31279375Smsmith /* 313133624Snjl * Flag the event handler for a manual invocation by our timeout. 314133624Snjl * We defer it like this so that the rest of the subsystem has time 315133624Snjl * to come up. Don't bother evaluating/printing the temperature at 316133624Snjl * this point; on many systems it'll be bogus until the EC is running. 31771874Smsmith */ 318133624Snjl sc->tz_flags |= TZ_FLAG_GETPROFILE; 31978999Smsmith 320133624Snjlout: 321133624Snjl if (error != 0) { 322133624Snjl EVENTHANDLER_DEREGISTER(power_profile_change, sc->tz_event); 323133624Snjl AcpiRemoveNotifyHandler(sc->tz_handle, ACPI_DEVICE_NOTIFY, 324133624Snjl acpi_tz_notify_handler); 325133624Snjl sysctl_ctx_free(&sc->tz_sysctl_ctx); 32691126Smsmith } 327119529Snjl return_VALUE (error); 32867761Smsmith} 32970271Stakawata 33078915Smsmith/* 33178915Smsmith * Parse the current state of this thermal zone and set up to use it. 33278915Smsmith * 33378915Smsmith * Note that we may have previous state, which will have to be discarded. 33478915Smsmith */ 33578915Smsmithstatic int 33678915Smsmithacpi_tz_establish(struct acpi_tz_softc *sc) 33778915Smsmith{ 33878915Smsmith ACPI_OBJECT *obj; 33978915Smsmith int i; 34078915Smsmith char nbuf[8]; 341148138Sume 34296926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 34378915Smsmith 344134909Snjl /* Erase any existing state. */ 34578915Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) 34679375Smsmith if (sc->tz_zone.al[i].Pointer != NULL) 34779375Smsmith AcpiOsFree(sc->tz_zone.al[i].Pointer); 34879375Smsmith if (sc->tz_zone.psl.Pointer != NULL) 34979375Smsmith AcpiOsFree(sc->tz_zone.psl.Pointer); 35078915Smsmith 351149449Sume /* 352149449Sume * XXX: We initialize only ACPI_BUFFER to avoid race condition 353149449Sume * with passive cooling thread which refers psv, tc1, tc2 and tsp. 354149449Sume */ 355149449Sume bzero(sc->tz_zone.ac, sizeof(sc->tz_zone.ac)); 356149449Sume bzero(sc->tz_zone.al, sizeof(sc->tz_zone.al)); 357149449Sume bzero(&sc->tz_zone.psl, sizeof(sc->tz_zone.psl)); 358149449Sume 359119529Snjl /* Evaluate thermal zone parameters. */ 36078915Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) { 36178915Smsmith sprintf(nbuf, "_AC%d", i); 36279375Smsmith acpi_tz_getparam(sc, nbuf, &sc->tz_zone.ac[i]); 36378915Smsmith sprintf(nbuf, "_AL%d", i); 36491126Smsmith sc->tz_zone.al[i].Length = ACPI_ALLOCATE_BUFFER; 36591126Smsmith sc->tz_zone.al[i].Pointer = NULL; 36691126Smsmith AcpiEvaluateObject(sc->tz_handle, nbuf, NULL, &sc->tz_zone.al[i]); 36779375Smsmith obj = (ACPI_OBJECT *)sc->tz_zone.al[i].Pointer; 36878915Smsmith if (obj != NULL) { 369119529Snjl /* Should be a package containing a list of power objects */ 37078915Smsmith if (obj->Type != ACPI_TYPE_PACKAGE) { 371119529Snjl device_printf(sc->tz_dev, "%s has unknown type %d, rejecting\n", 37278915Smsmith nbuf, obj->Type); 373119529Snjl return_VALUE (ENXIO); 37478915Smsmith } 37578915Smsmith } 37678915Smsmith } 37779375Smsmith acpi_tz_getparam(sc, "_CRT", &sc->tz_zone.crt); 37879375Smsmith acpi_tz_getparam(sc, "_HOT", &sc->tz_zone.hot); 37991126Smsmith sc->tz_zone.psl.Length = ACPI_ALLOCATE_BUFFER; 38091126Smsmith sc->tz_zone.psl.Pointer = NULL; 38191126Smsmith AcpiEvaluateObject(sc->tz_handle, "_PSL", NULL, &sc->tz_zone.psl); 38279375Smsmith acpi_tz_getparam(sc, "_PSV", &sc->tz_zone.psv); 38379375Smsmith acpi_tz_getparam(sc, "_TC1", &sc->tz_zone.tc1); 38479375Smsmith acpi_tz_getparam(sc, "_TC2", &sc->tz_zone.tc2); 38579375Smsmith acpi_tz_getparam(sc, "_TSP", &sc->tz_zone.tsp); 38679375Smsmith acpi_tz_getparam(sc, "_TZP", &sc->tz_zone.tzp); 38778915Smsmith 38878915Smsmith /* 38979283Smsmith * Sanity-check the values we've been given. 39079283Smsmith * 39179283Smsmith * XXX what do we do about systems that give us the same value for 39279283Smsmith * more than one of these setpoints? 39379283Smsmith */ 39479375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.crt, "_CRT"); 39579375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.hot, "_HOT"); 39679375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.psv, "_PSV"); 39779283Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) 39879375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.ac[i], "_ACx"); 39979283Smsmith 400119529Snjl return_VALUE (0); 40178915Smsmith} 40278915Smsmith 403133624Snjlstatic char *aclevel_string[] = { 404133624Snjl "NONE", "_AC0", "_AC1", "_AC2", "_AC3", "_AC4", 405133624Snjl "_AC5", "_AC6", "_AC7", "_AC8", "_AC9" 406133624Snjl}; 40785699Siwasaki 40885699Siwasakistatic __inline const char * 40985699Siwasakiacpi_tz_aclevel_string(int active) 41085699Siwasaki{ 411133624Snjl if (active < -1 || active >= TZ_NUMLEVELS) 412133624Snjl return (aclevel_string[0]); 41385699Siwasaki 414133624Snjl return (aclevel_string[active + 1]); 41585699Siwasaki} 41685699Siwasaki 41778915Smsmith/* 418149450Sume * Get the current temperature. 419149450Sume */ 420149450Sumestatic int 421149450Sumeacpi_tz_get_temperature(struct acpi_tz_softc *sc) 422149450Sume{ 423149450Sume int temp; 424149450Sume ACPI_STATUS status; 425149450Sume 426149482Skan ACPI_FUNCTION_NAME ("acpi_tz_get_temperature"); 427149482Skan 428149450Sume status = acpi_GetInteger(sc->tz_handle, "_TMP", &temp); 429149450Sume if (ACPI_FAILURE(status)) { 430149450Sume ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 431149450Sume "error fetching current temperature -- %s\n", 432149450Sume AcpiFormatException(status)); 433149450Sume return (FALSE); 434149450Sume } 435149450Sume 436149450Sume ACPI_DEBUG_PRINT((ACPI_DB_VALUES, "got %d.%dC\n", TZ_KELVTOC(temp))); 437149450Sume sc->tz_temperature = temp; 438149450Sume return (TRUE); 439149450Sume} 440149450Sume 441149450Sume/* 44278915Smsmith * Evaluate the condition of a thermal zone, take appropriate actions. 44378915Smsmith */ 44471874Smsmithstatic void 445119529Snjlacpi_tz_monitor(void *Context) 44671874Smsmith{ 447119529Snjl struct acpi_tz_softc *sc; 448119529Snjl struct timespec curtime; 44979283Smsmith int temp; 45078915Smsmith int i; 45179283Smsmith int newactive, newflags; 45270271Stakawata 45396926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 45470271Stakawata 455119529Snjl sc = (struct acpi_tz_softc *)Context; 45688420Siwasaki 457119529Snjl /* Get the current temperature. */ 458149450Sume if (!acpi_tz_get_temperature(sc)) { 45978915Smsmith /* XXX disable zone? go to max cooling? */ 460133624Snjl return_VOID; 46171874Smsmith } 462149450Sume temp = sc->tz_temperature; 46388420Siwasaki 46478915Smsmith /* 46578915Smsmith * Work out what we ought to be doing right now. 46679283Smsmith * 46779283Smsmith * Note that the _ACx levels sort from hot to cold. 46878915Smsmith */ 46979283Smsmith newactive = TZ_ACTIVE_NONE; 47079375Smsmith for (i = TZ_NUMLEVELS - 1; i >= 0; i--) { 471142195Snjl if (sc->tz_zone.ac[i] != -1 && temp >= sc->tz_zone.ac[i]) { 47279283Smsmith newactive = i; 47382967Siwasaki if (sc->tz_active != newactive) { 474119529Snjl ACPI_VPRINT(sc->tz_dev, 475119529Snjl acpi_device_get_parent_softc(sc->tz_dev), 476119529Snjl "_AC%d: temperature %d.%d >= setpoint %d.%d\n", i, 477119529Snjl TZ_KELVTOC(temp), TZ_KELVTOC(sc->tz_zone.ac[i])); 47882967Siwasaki } 47979375Smsmith } 48079375Smsmith } 48179283Smsmith 48285699Siwasaki /* 48385699Siwasaki * We are going to get _ACx level down (colder side), but give a guaranteed 48485699Siwasaki * minimum cooling run time if requested. 48585699Siwasaki */ 48685699Siwasaki if (acpi_tz_min_runtime > 0 && sc->tz_active != TZ_ACTIVE_NONE && 48785699Siwasaki (newactive == TZ_ACTIVE_NONE || newactive > sc->tz_active)) { 488119529Snjl 48985699Siwasaki getnanotime(&curtime); 49085699Siwasaki timespecsub(&curtime, &sc->tz_cooling_started); 491119529Snjl if (curtime.tv_sec < acpi_tz_min_runtime) 49285699Siwasaki newactive = sc->tz_active; 49385699Siwasaki } 49485699Siwasaki 495119529Snjl /* Handle user override of active mode */ 496126662Snjl if (sc->tz_requested != TZ_ACTIVE_NONE && sc->tz_requested < newactive) 49779375Smsmith newactive = sc->tz_requested; 49878915Smsmith 49979375Smsmith /* update temperature-related flags */ 50079375Smsmith newflags = TZ_THFLAG_NONE; 501124439Snjl if (sc->tz_zone.psv != -1 && temp >= sc->tz_zone.psv) 50279375Smsmith newflags |= TZ_THFLAG_PSV; 503124439Snjl if (sc->tz_zone.hot != -1 && temp >= sc->tz_zone.hot) 50479375Smsmith newflags |= TZ_THFLAG_HOT; 505124439Snjl if (sc->tz_zone.crt != -1 && temp >= sc->tz_zone.crt) 50679375Smsmith newflags |= TZ_THFLAG_CRT; 50779375Smsmith 508119529Snjl /* If the active cooling state has changed, we have to switch things. */ 50979283Smsmith if (newactive != sc->tz_active) { 510119529Snjl /* Turn off the cooling devices that are on, if any are */ 51179283Smsmith if (sc->tz_active != TZ_ACTIVE_NONE) 512119529Snjl acpi_ForeachPackageObject( 513119529Snjl (ACPI_OBJECT *)sc->tz_zone.al[sc->tz_active].Pointer, 514119529Snjl acpi_tz_switch_cooler_off, sc); 51578915Smsmith 516119529Snjl /* Turn on cooling devices that are required, if any are */ 517119529Snjl if (newactive != TZ_ACTIVE_NONE) { 518119529Snjl acpi_ForeachPackageObject( 519119529Snjl (ACPI_OBJECT *)sc->tz_zone.al[newactive].Pointer, 520119529Snjl acpi_tz_switch_cooler_on, sc); 521119529Snjl } 52286552Siwasaki ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 523119529Snjl "switched from %s to %s: %d.%dC\n", 524119529Snjl acpi_tz_aclevel_string(sc->tz_active), 525119529Snjl acpi_tz_aclevel_string(newactive), TZ_KELVTOC(temp)); 52679283Smsmith sc->tz_active = newactive; 527142195Snjl getnanotime(&sc->tz_cooling_started); 52879283Smsmith } 52978915Smsmith 530119529Snjl /* XXX (de)activate any passive cooling that may be required. */ 53178915Smsmith 53278915Smsmith /* 533125335Snjl * If the temperature is at _HOT or _CRT, increment our event count. 534125335Snjl * If it has occurred enough times, shutdown the system. This is 535125335Snjl * needed because some systems will report an invalid high temperature 536125335Snjl * for one poll cycle. It is suspected this is due to the embedded 537125335Snjl * controller timing out. A typical value is 138C for one cycle on 538125335Snjl * a system that is otherwise 65C. 539125366Snjl * 540125366Snjl * If we're almost at that threshold, notify the user through devd(8). 54178915Smsmith */ 542125335Snjl if ((newflags & (TZ_THFLAG_HOT | TZ_THFLAG_CRT)) != 0) { 543125366Snjl sc->tz_validchecks++; 544125366Snjl if (sc->tz_validchecks == TZ_VALIDCHECKS) { 545125335Snjl device_printf(sc->tz_dev, 546125335Snjl "WARNING - current temperature (%d.%dC) exceeds safe limits\n", 547125335Snjl TZ_KELVTOC(sc->tz_temperature)); 548125335Snjl shutdown_nice(RB_POWEROFF); 549125366Snjl } else if (sc->tz_validchecks == TZ_NOTIFYCOUNT) 550125366Snjl acpi_UserNotify("Thermal", sc->tz_handle, TZ_NOTIFY_CRITICAL); 551125335Snjl } else { 552125335Snjl sc->tz_validchecks = 0; 55378915Smsmith } 55479375Smsmith sc->tz_thflags = newflags; 55578915Smsmith 55671874Smsmith return_VOID; 55771874Smsmith} 55870271Stakawata 55978915Smsmith/* 560148138Sume * Given an object, verify that it's a reference to a device of some sort, 56178915Smsmith * and try to switch it off. 56278915Smsmith */ 56378915Smsmithstatic void 56478915Smsmithacpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg) 56578915Smsmith{ 566128047Snjl ACPI_HANDLE cooler; 56778915Smsmith 56896926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 56978915Smsmith 570128047Snjl cooler = acpi_GetReference(NULL, obj); 571128047Snjl if (cooler == NULL) { 572128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get handle\n")); 573128047Snjl return_VOID; 574128047Snjl } 575102470Siwasaki 576128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s off\n", 577128047Snjl acpi_name(cooler))); 578128150Snjl acpi_pwr_switch_consumer(cooler, ACPI_STATE_D3); 579119529Snjl 58079375Smsmith return_VOID; 58178915Smsmith} 58278915Smsmith 58378915Smsmith/* 584148138Sume * Given an object, verify that it's a reference to a device of some sort, 58578915Smsmith * and try to switch it on. 58678915Smsmith * 587128047Snjl * XXX replication of off/on function code is bad. 58878915Smsmith */ 58978915Smsmithstatic void 59078915Smsmithacpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg) 59178915Smsmith{ 59278915Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg; 59378999Smsmith ACPI_HANDLE cooler; 59479375Smsmith ACPI_STATUS status; 595148138Sume 59696926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 59778915Smsmith 598128047Snjl cooler = acpi_GetReference(NULL, obj); 599128047Snjl if (cooler == NULL) { 600128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get handle\n")); 601128047Snjl return_VOID; 602128047Snjl } 603102470Siwasaki 604128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s on\n", 605128047Snjl acpi_name(cooler))); 606128047Snjl status = acpi_pwr_switch_consumer(cooler, ACPI_STATE_D0); 607128047Snjl if (ACPI_FAILURE(status)) { 608128047Snjl ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 609128047Snjl "failed to activate %s - %s\n", acpi_name(cooler), 610128047Snjl AcpiFormatException(status)); 61178915Smsmith } 612119529Snjl 613119529Snjl return_VOID; 61478915Smsmith} 61578915Smsmith 61678915Smsmith/* 61778915Smsmith * Read/debug-print a parameter, default it to -1. 61878915Smsmith */ 61978915Smsmithstatic void 62078915Smsmithacpi_tz_getparam(struct acpi_tz_softc *sc, char *node, int *data) 62178915Smsmith{ 62278915Smsmith 62396926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 62478915Smsmith 625126560Snjl if (ACPI_FAILURE(acpi_GetInteger(sc->tz_handle, node, data))) { 62678915Smsmith *data = -1; 62778915Smsmith } else { 628119529Snjl ACPI_DEBUG_PRINT((ACPI_DB_VALUES, "%s.%s = %d\n", 629119529Snjl acpi_name(sc->tz_handle), node, *data)); 63078915Smsmith } 631119529Snjl 632148138Sume return_VOID; 63378915Smsmith} 63479283Smsmith 63579283Smsmith/* 63679283Smsmith * Sanity-check a temperature value. Assume that setpoints 63779283Smsmith * should be between 0C and 150C. 63879283Smsmith */ 63979283Smsmithstatic void 64079283Smsmithacpi_tz_sanity(struct acpi_tz_softc *sc, int *val, char *what) 64179283Smsmith{ 642119529Snjl if (*val != -1 && (*val < TZ_ZEROC || *val > TZ_ZEROC + 1500)) { 64379283Smsmith device_printf(sc->tz_dev, "%s value is absurd, ignored (%d.%dC)\n", 64479283Smsmith what, TZ_KELVTOC(*val)); 64579283Smsmith *val = -1; 64679283Smsmith } 64779283Smsmith} 64879375Smsmith 64979375Smsmith/* 65079375Smsmith * Respond to a sysctl on the active state node. 651148138Sume */ 65279375Smsmithstatic int 65379375Smsmithacpi_tz_active_sysctl(SYSCTL_HANDLER_ARGS) 65479375Smsmith{ 65579375Smsmith struct acpi_tz_softc *sc; 65679375Smsmith int active; 65779375Smsmith int error; 65879375Smsmith 65979375Smsmith sc = (struct acpi_tz_softc *)oidp->oid_arg1; 66079375Smsmith active = sc->tz_active; 66179375Smsmith error = sysctl_handle_int(oidp, &active, 0, req); 66279375Smsmith 663119529Snjl /* Error or no new value */ 664119529Snjl if (error != 0 || req->newptr == NULL) 665133624Snjl return (error); 666133624Snjl if (active < -1 || active >= TZ_NUMLEVELS) 667133624Snjl return (EINVAL); 66879375Smsmith 669119529Snjl /* Set new preferred level and re-switch */ 67079375Smsmith sc->tz_requested = active; 671133624Snjl acpi_tz_signal(sc, 0); 672133624Snjl return (0); 67379375Smsmith} 67479375Smsmith 675148138Sumestatic int 676148138Sumeacpi_tz_cooling_sysctl(SYSCTL_HANDLER_ARGS) 677148138Sume{ 678148138Sume struct acpi_tz_softc *sc; 679148138Sume int enabled, error; 680148138Sume 681148138Sume sc = (struct acpi_tz_softc *)oidp->oid_arg1; 682148138Sume enabled = sc->tz_cooling_enabled; 683148138Sume error = sysctl_handle_int(oidp, &enabled, 0, req); 684148138Sume 685148138Sume /* Error or no new value */ 686148138Sume if (error != 0 || req->newptr == NULL) 687148138Sume return (error); 688148138Sume if (enabled != TRUE && enabled != FALSE) 689148138Sume return (EINVAL); 690148138Sume 691148138Sume if (enabled) { 692148138Sume if (acpi_tz_cooling_is_available(sc)) 693148138Sume error = acpi_tz_cooling_thread_start(sc); 694148138Sume else 695148138Sume error = ENODEV; 696148138Sume if (error) 697148138Sume enabled = FALSE; 698148138Sume } 699148138Sume sc->tz_cooling_enabled = enabled; 700148138Sume return (error); 701148138Sume} 702148138Sume 70378915Smsmithstatic void 70471874Smsmithacpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context) 70571874Smsmith{ 70678915Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)context; 70778915Smsmith 70896926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 70970271Stakawata 710133624Snjl switch (notify) { 71178915Smsmith case TZ_NOTIFY_TEMPERATURE: 712119529Snjl /* Temperature change occurred */ 713133624Snjl acpi_tz_signal(sc, 0); 71478915Smsmith break; 71578915Smsmith case TZ_NOTIFY_DEVICES: 71678915Smsmith case TZ_NOTIFY_LEVELS: 717119529Snjl /* Zone devices/setpoints changed */ 718133624Snjl acpi_tz_signal(sc, TZ_FLAG_GETSETTINGS); 71978915Smsmith break; 72078915Smsmith default: 72186552Siwasaki ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 722119529Snjl "unknown Notify event 0x%x\n", notify); 72378915Smsmith break; 72471874Smsmith } 725119529Snjl 726121493Snjl acpi_UserNotify("Thermal", h, notify); 727121493Snjl 72871874Smsmith return_VOID; 72971874Smsmith} 73070271Stakawata 731133624Snjlstatic void 732133624Snjlacpi_tz_signal(struct acpi_tz_softc *sc, int flags) 733133624Snjl{ 734133624Snjl ACPI_LOCK(thermal); 735133624Snjl sc->tz_flags |= flags; 736133624Snjl ACPI_UNLOCK(thermal); 737133624Snjl wakeup(&acpi_tz_proc); 738133624Snjl} 739133624Snjl 74078915Smsmith/* 741134909Snjl * Notifies can be generated asynchronously but have also been seen to be 742134909Snjl * triggered by other thermal methods. One system generates a notify of 743134909Snjl * 0x81 when the fan is turned on or off. Another generates it when _SCP 744134909Snjl * is called. To handle these situations, we check the zone via 745134909Snjl * acpi_tz_monitor() before evaluating changes to setpoints or the cooling 746134909Snjl * policy. 74778915Smsmith */ 74878915Smsmithstatic void 749133624Snjlacpi_tz_timeout(struct acpi_tz_softc *sc, int flags) 75078915Smsmith{ 751134909Snjl 752134909Snjl /* Check the current temperature and take action based on it */ 753134909Snjl acpi_tz_monitor(sc); 754134909Snjl 755133624Snjl /* If requested, get the power profile settings. */ 756133624Snjl if (flags & TZ_FLAG_GETPROFILE) 757133624Snjl acpi_tz_power_profile(sc); 75879375Smsmith 759134909Snjl /* 760134909Snjl * If requested, check for new devices/setpoints. After finding them, 761134909Snjl * check if we need to switch fans based on the new values. 762134909Snjl */ 763134909Snjl if (flags & TZ_FLAG_GETSETTINGS) { 764133624Snjl acpi_tz_establish(sc); 765134909Snjl acpi_tz_monitor(sc); 766134909Snjl } 76778915Smsmith 76878915Smsmith /* XXX passive cooling actions? */ 76978915Smsmith} 77079375Smsmith 77179375Smsmith/* 77279375Smsmith * System power profile may have changed; fetch and notify the 77379375Smsmith * thermal zone accordingly. 77479375Smsmith * 77579375Smsmith * Since this can be called from an arbitrary eventhandler, it needs 77679375Smsmith * to get the ACPI lock itself. 77779375Smsmith */ 77879375Smsmithstatic void 77991640Siwasakiacpi_tz_power_profile(void *arg) 78079375Smsmith{ 78179375Smsmith ACPI_STATUS status; 78279375Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg; 78391640Siwasaki int state; 78479375Smsmith 78591640Siwasaki state = power_profile_get_state(); 786119529Snjl if (state != POWER_PROFILE_PERFORMANCE && state != POWER_PROFILE_ECONOMY) 787119529Snjl return; 78891640Siwasaki 78979375Smsmith /* check that we haven't decided there's no _SCP method */ 790119529Snjl if ((sc->tz_flags & TZ_FLAG_NO_SCP) == 0) { 79179375Smsmith 792119529Snjl /* Call _SCP to set the new profile */ 793148138Sume status = acpi_SetInteger(sc->tz_handle, "_SCP", 794126560Snjl (state == POWER_PROFILE_PERFORMANCE) ? 0 : 1); 795119529Snjl if (ACPI_FAILURE(status)) { 79679385Smsmith if (status != AE_NOT_FOUND) 797119529Snjl ACPI_VPRINT(sc->tz_dev, 798119529Snjl acpi_device_get_parent_softc(sc->tz_dev), 799119529Snjl "can't evaluate %s._SCP - %s\n", 800119529Snjl acpi_name(sc->tz_handle), 801119529Snjl AcpiFormatException(status)); 80279375Smsmith sc->tz_flags |= TZ_FLAG_NO_SCP; 80379375Smsmith } else { 804119529Snjl /* We have to re-evaluate the entire zone now */ 805133624Snjl acpi_tz_signal(sc, TZ_FLAG_GETSETTINGS); 80679375Smsmith } 80779375Smsmith } 80879375Smsmith} 80979375Smsmith 81091126Smsmith/* 81191126Smsmith * Thermal zone monitor thread. 81291126Smsmith */ 81391126Smsmithstatic void 81491126Smsmithacpi_tz_thread(void *arg) 81591126Smsmith{ 81691126Smsmith device_t *devs; 81791126Smsmith int devcount, i; 818133624Snjl int flags; 819133624Snjl struct acpi_tz_softc **sc; 82091126Smsmith 82196926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 82291126Smsmith 82391126Smsmith devs = NULL; 82491126Smsmith devcount = 0; 825133624Snjl sc = NULL; 82691126Smsmith 82791126Smsmith for (;;) { 828133624Snjl /* If the number of devices has changed, re-evaluate. */ 829133624Snjl if (devclass_get_maxunit(acpi_tz_devclass) != devcount) { 830133624Snjl if (devs != NULL) { 831133624Snjl free(devs, M_TEMP); 832133624Snjl free(sc, M_TEMP); 833133624Snjl } 834133624Snjl devclass_get_devices(acpi_tz_devclass, &devs, &devcount); 835133624Snjl sc = malloc(sizeof(struct acpi_tz_softc *) * devcount, M_TEMP, 836133624Snjl M_WAITOK | M_ZERO); 837133624Snjl for (i = 0; i < devcount; i++) 838133624Snjl sc[i] = device_get_softc(devs[i]); 839133624Snjl } 84091126Smsmith 841133624Snjl /* Check for temperature events and act on them. */ 842133624Snjl for (i = 0; i < devcount; i++) { 843133624Snjl ACPI_LOCK(thermal); 844133624Snjl flags = sc[i]->tz_flags; 845133624Snjl sc[i]->tz_flags &= TZ_FLAG_NO_SCP; 846133624Snjl ACPI_UNLOCK(thermal); 847133624Snjl acpi_tz_timeout(sc[i], flags); 848133624Snjl } 84991215Smsmith 850133624Snjl /* If more work to do, don't go to sleep yet. */ 851133624Snjl ACPI_LOCK(thermal); 852133624Snjl for (i = 0; i < devcount; i++) { 853133624Snjl if (sc[i]->tz_flags & ~TZ_FLAG_NO_SCP) 854133624Snjl break; 855133624Snjl } 85691126Smsmith 857133624Snjl /* 858133624Snjl * If we have no more work, sleep for a while, setting PDROP so that 859133624Snjl * the mutex will not be reacquired. Otherwise, drop the mutex and 860133624Snjl * loop to handle more events. 861133624Snjl */ 862133624Snjl if (i == devcount) 863133624Snjl msleep(&acpi_tz_proc, &thermal_mutex, PZERO | PDROP, "tzpoll", 864133624Snjl hz * acpi_tz_polling_rate); 865133624Snjl else 866133624Snjl ACPI_UNLOCK(thermal); 86791126Smsmith } 86891126Smsmith} 869148138Sume 870148138Sumestatic int 871148138Sumeacpi_tz_cpufreq_restore(struct acpi_tz_softc *sc) 872148138Sume{ 873148138Sume device_t dev; 874148138Sume int error; 875148138Sume 876148138Sume if (!sc->tz_cooling_updated) 877148138Sume return (0); 878148138Sume if ((dev = devclass_get_device(devclass_find("cpufreq"), 0)) == NULL) 879148138Sume return (ENXIO); 880148138Sume ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 881149201Sume "temperature %d.%dC: resuming previous clock speed (%d MHz)\n", 882149201Sume TZ_KELVTOC(sc->tz_temperature), sc->tz_cooling_saved_freq); 883148138Sume error = CPUFREQ_SET(dev, NULL, CPUFREQ_PRIO_KERN); 884148138Sume if (error == 0) 885148138Sume sc->tz_cooling_updated = FALSE; 886148138Sume return (error); 887148138Sume} 888148138Sume 889148138Sumestatic int 890148138Sumeacpi_tz_cpufreq_update(struct acpi_tz_softc *sc, int req) 891148138Sume{ 892148138Sume device_t dev; 893148138Sume struct cf_level *levels; 894148138Sume int num_levels, error, freq, desired_freq, perf, i; 895148138Sume 896148138Sume levels = malloc(CPUFREQ_MAX_LEVELS * sizeof(*levels), M_TEMP, M_NOWAIT); 897148138Sume if (levels == NULL) 898148138Sume return (ENOMEM); 899148138Sume 900148138Sume /* 901148138Sume * Find the main device, cpufreq0. We don't yet support independent 902148138Sume * CPU frequency control on SMP. 903148138Sume */ 904148138Sume if ((dev = devclass_get_device(devclass_find("cpufreq"), 0)) == NULL) { 905148138Sume error = ENXIO; 906148138Sume goto out; 907148138Sume } 908148138Sume 909148138Sume /* Get the current frequency. */ 910148138Sume error = CPUFREQ_GET(dev, &levels[0]); 911148138Sume if (error) 912148138Sume goto out; 913148138Sume freq = levels[0].total_set.freq; 914148138Sume 915148138Sume /* Get the current available frequency levels. */ 916148138Sume num_levels = CPUFREQ_MAX_LEVELS; 917148138Sume error = CPUFREQ_LEVELS(dev, levels, &num_levels); 918148138Sume if (error) { 919148138Sume if (error == E2BIG) 920148138Sume printf("cpufreq: need to increase CPUFREQ_MAX_LEVELS\n"); 921148138Sume goto out; 922148138Sume } 923148138Sume 924148138Sume /* Calculate the desired frequency as a percent of the max frequency. */ 925148138Sume perf = 100 * freq / levels[0].total_set.freq - req; 926148138Sume if (perf < 0) 927148138Sume perf = 0; 928148138Sume else if (perf > 100) 929148138Sume perf = 100; 930148138Sume desired_freq = levels[0].total_set.freq * perf / 100; 931148138Sume 932149201Sume if (desired_freq < freq) { 933148138Sume /* Find the closest available frequency, rounding down. */ 934148138Sume for (i = 0; i < num_levels; i++) 935148138Sume if (levels[i].total_set.freq <= desired_freq) 936148138Sume break; 937148138Sume 938148138Sume /* If we didn't find a relevant setting, use the lowest. */ 939148138Sume if (i == num_levels) 940148138Sume i--; 941148138Sume } else { 942149201Sume /* If we didn't decrease frequency yet, don't increase it. */ 943149201Sume if (!sc->tz_cooling_updated) { 944149201Sume sc->tz_cooling_active = FALSE; 945149201Sume goto out; 946149201Sume } 947149201Sume 948149201Sume /* Use saved cpu frequency as maximum value. */ 949149201Sume if (desired_freq > sc->tz_cooling_saved_freq) 950149201Sume desired_freq = sc->tz_cooling_saved_freq; 951149201Sume 952148138Sume /* Find the closest available frequency, rounding up. */ 953148138Sume for (i = num_levels - 1; i >= 0; i--) 954148138Sume if (levels[i].total_set.freq >= desired_freq) 955148138Sume break; 956148138Sume 957148138Sume /* If we didn't find a relevant setting, use the highest. */ 958148138Sume if (i == -1) 959148138Sume i++; 960148138Sume 961149201Sume /* If we're going to the highest frequency, restore the old setting. */ 962149201Sume if (i == 0 || desired_freq == sc->tz_cooling_saved_freq) { 963149201Sume error = acpi_tz_cpufreq_restore(sc); 964149201Sume if (error == 0) 965149201Sume sc->tz_cooling_active = FALSE; 966149201Sume goto out; 967149201Sume } 968148138Sume } 969148138Sume 970148138Sume /* If we are going to a new frequency, activate it. */ 971148138Sume if (levels[i].total_set.freq != freq) { 972148138Sume ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 973148138Sume "temperature %d.%dC: %screasing clock speed " 974148138Sume "from %d MHz to %d MHz\n", 975148138Sume TZ_KELVTOC(sc->tz_temperature), 976148138Sume (freq > levels[i].total_set.freq) ? "de" : "in", 977148138Sume freq, levels[i].total_set.freq); 978148138Sume error = CPUFREQ_SET(dev, &levels[i], CPUFREQ_PRIO_KERN); 979149201Sume if (error == 0 && !sc->tz_cooling_updated) { 980149201Sume sc->tz_cooling_saved_freq = freq; 981148138Sume sc->tz_cooling_updated = TRUE; 982149201Sume } 983148138Sume } 984148138Sume 985148138Sumeout: 986148138Sume if (levels) 987148138Sume free(levels, M_TEMP); 988148138Sume return (error); 989148138Sume} 990148138Sume 991148138Sume/* 992148138Sume * Passive cooling thread; monitors current temperature according to the 993148138Sume * cooling interval and calculates whether to scale back CPU frequency. 994148138Sume */ 995148138Sumestatic void 996148138Sumeacpi_tz_cooling_thread(void *arg) 997148138Sume{ 998148138Sume struct acpi_tz_softc *sc; 999149450Sume int error, perf, curr_temp, prev_temp; 1000148138Sume 1001148138Sume ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 1002148138Sume 1003148138Sume sc = (struct acpi_tz_softc *)arg; 1004148138Sume 1005149450Sume prev_temp = sc->tz_temperature; 1006148138Sume while (sc->tz_cooling_enabled) { 1007149450Sume if (sc->tz_cooling_active) 1008149450Sume (void)acpi_tz_get_temperature(sc); 1009149450Sume curr_temp = sc->tz_temperature; 1010149450Sume if (curr_temp >= sc->tz_zone.psv) 1011148138Sume sc->tz_cooling_active = TRUE; 1012148138Sume if (sc->tz_cooling_active) { 1013149450Sume perf = sc->tz_zone.tc1 * (curr_temp - prev_temp) + 1014149450Sume sc->tz_zone.tc2 * (curr_temp - sc->tz_zone.psv); 1015148138Sume perf /= 10; 1016148138Sume 1017148138Sume if (perf != 0) { 1018148138Sume error = acpi_tz_cpufreq_update(sc, perf); 1019148138Sume 1020148138Sume /* 1021148138Sume * If error and not simply a higher priority setting was 1022148138Sume * active, disable cooling. 1023148138Sume */ 1024148138Sume if (error != 0 && error != EPERM) { 1025148138Sume device_printf(sc->tz_dev, 1026148138Sume "failed to set new freq, disabling passive cooling\n"); 1027148138Sume sc->tz_cooling_enabled = FALSE; 1028148138Sume } 1029148138Sume } 1030148138Sume } 1031149450Sume prev_temp = curr_temp; 1032148138Sume tsleep(&sc->tz_cooling_proc, PZERO, "cooling", 1033148138Sume hz * sc->tz_zone.tsp / 10); 1034148138Sume } 1035148138Sume if (sc->tz_cooling_active) { 1036148138Sume acpi_tz_cpufreq_restore(sc); 1037148138Sume sc->tz_cooling_active = FALSE; 1038148138Sume } 1039148703Sume sc->tz_cooling_proc = NULL; 1040148138Sume ACPI_LOCK(thermal); 1041148703Sume sc->tz_cooling_proc_running = FALSE; 1042148138Sume ACPI_UNLOCK(thermal); 1043148138Sume kthread_exit(0); 1044148138Sume} 1045148138Sume 1046148138Sume/* 1047148138Sume * TODO: We ignore _PSL (list of cooling devices) since cpufreq enumerates 1048148138Sume * all CPUs for us. However, it's possible in the future _PSL will 1049148138Sume * reference non-CPU devices so we may want to support it then. 1050148138Sume */ 1051148138Sumestatic int 1052148138Sumeacpi_tz_cooling_is_available(struct acpi_tz_softc *sc) 1053148138Sume{ 1054148138Sume return (sc->tz_zone.tc1 != -1 && sc->tz_zone.tc2 != -1 && 1055148138Sume sc->tz_zone.tsp != -1 && sc->tz_zone.tsp != 0 && 1056148138Sume sc->tz_zone.psv != -1); 1057148138Sume} 1058148138Sume 1059148138Sumestatic int 1060148138Sumeacpi_tz_cooling_thread_start(struct acpi_tz_softc *sc) 1061148138Sume{ 1062148138Sume int error; 1063148138Sume char name[16]; 1064148138Sume 1065148703Sume ACPI_LOCK(thermal); 1066148703Sume if (sc->tz_cooling_proc_running) { 1067148703Sume ACPI_UNLOCK(thermal); 1068148703Sume return (0); 1069148703Sume } 1070148703Sume sc->tz_cooling_proc_running = TRUE; 1071148703Sume ACPI_UNLOCK(thermal); 1072148138Sume error = 0; 1073148138Sume if (sc->tz_cooling_proc == NULL) { 1074148138Sume snprintf(name, sizeof(name), "acpi_cooling%d", 1075148138Sume device_get_unit(sc->tz_dev)); 1076148138Sume error = kthread_create(acpi_tz_cooling_thread, sc, 1077148138Sume &sc->tz_cooling_proc, RFHIGHPID, 0, name); 1078148703Sume if (error != 0) { 1079148138Sume device_printf(sc->tz_dev, "could not create thread - %d", error); 1080148703Sume ACPI_LOCK(thermal); 1081148703Sume sc->tz_cooling_proc_running = FALSE; 1082148703Sume ACPI_UNLOCK(thermal); 1083148703Sume } 1084148138Sume } 1085148138Sume return (error); 1086148138Sume} 1087