acpi_thermal.c revision 149449
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 149449 2005-08-25 10:50:36Z ume $"); 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/* 41878915Smsmith * Evaluate the condition of a thermal zone, take appropriate actions. 41978915Smsmith */ 42071874Smsmithstatic void 421119529Snjlacpi_tz_monitor(void *Context) 42271874Smsmith{ 423119529Snjl struct acpi_tz_softc *sc; 424119529Snjl struct timespec curtime; 42579283Smsmith int temp; 42678915Smsmith int i; 42779283Smsmith int newactive, newflags; 42886399Siwasaki ACPI_STATUS status; 42970271Stakawata 43096926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 43170271Stakawata 432119529Snjl sc = (struct acpi_tz_softc *)Context; 43388420Siwasaki 434119529Snjl /* Get the current temperature. */ 435126560Snjl status = acpi_GetInteger(sc->tz_handle, "_TMP", &temp); 436119529Snjl if (ACPI_FAILURE(status)) { 43786552Siwasaki ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 43886552Siwasaki "error fetching current temperature -- %s\n", 43986552Siwasaki AcpiFormatException(status)); 44078915Smsmith /* XXX disable zone? go to max cooling? */ 441133624Snjl return_VOID; 44271874Smsmith } 44388420Siwasaki 44482372Smsmith ACPI_DEBUG_PRINT((ACPI_DB_VALUES, "got %d.%dC\n", TZ_KELVTOC(temp))); 44579283Smsmith sc->tz_temperature = temp; 44678915Smsmith 44778915Smsmith /* 44878915Smsmith * Work out what we ought to be doing right now. 44979283Smsmith * 45079283Smsmith * Note that the _ACx levels sort from hot to cold. 45178915Smsmith */ 45279283Smsmith newactive = TZ_ACTIVE_NONE; 45379375Smsmith for (i = TZ_NUMLEVELS - 1; i >= 0; i--) { 454142195Snjl if (sc->tz_zone.ac[i] != -1 && temp >= sc->tz_zone.ac[i]) { 45579283Smsmith newactive = i; 45682967Siwasaki if (sc->tz_active != newactive) { 457119529Snjl ACPI_VPRINT(sc->tz_dev, 458119529Snjl acpi_device_get_parent_softc(sc->tz_dev), 459119529Snjl "_AC%d: temperature %d.%d >= setpoint %d.%d\n", i, 460119529Snjl TZ_KELVTOC(temp), TZ_KELVTOC(sc->tz_zone.ac[i])); 46182967Siwasaki } 46279375Smsmith } 46379375Smsmith } 46479283Smsmith 46585699Siwasaki /* 46685699Siwasaki * We are going to get _ACx level down (colder side), but give a guaranteed 46785699Siwasaki * minimum cooling run time if requested. 46885699Siwasaki */ 46985699Siwasaki if (acpi_tz_min_runtime > 0 && sc->tz_active != TZ_ACTIVE_NONE && 47085699Siwasaki (newactive == TZ_ACTIVE_NONE || newactive > sc->tz_active)) { 471119529Snjl 47285699Siwasaki getnanotime(&curtime); 47385699Siwasaki timespecsub(&curtime, &sc->tz_cooling_started); 474119529Snjl if (curtime.tv_sec < acpi_tz_min_runtime) 47585699Siwasaki newactive = sc->tz_active; 47685699Siwasaki } 47785699Siwasaki 478119529Snjl /* Handle user override of active mode */ 479126662Snjl if (sc->tz_requested != TZ_ACTIVE_NONE && sc->tz_requested < newactive) 48079375Smsmith newactive = sc->tz_requested; 48178915Smsmith 48279375Smsmith /* update temperature-related flags */ 48379375Smsmith newflags = TZ_THFLAG_NONE; 484124439Snjl if (sc->tz_zone.psv != -1 && temp >= sc->tz_zone.psv) 48579375Smsmith newflags |= TZ_THFLAG_PSV; 486124439Snjl if (sc->tz_zone.hot != -1 && temp >= sc->tz_zone.hot) 48779375Smsmith newflags |= TZ_THFLAG_HOT; 488124439Snjl if (sc->tz_zone.crt != -1 && temp >= sc->tz_zone.crt) 48979375Smsmith newflags |= TZ_THFLAG_CRT; 49079375Smsmith 491119529Snjl /* If the active cooling state has changed, we have to switch things. */ 49279283Smsmith if (newactive != sc->tz_active) { 493119529Snjl /* Turn off the cooling devices that are on, if any are */ 49479283Smsmith if (sc->tz_active != TZ_ACTIVE_NONE) 495119529Snjl acpi_ForeachPackageObject( 496119529Snjl (ACPI_OBJECT *)sc->tz_zone.al[sc->tz_active].Pointer, 497119529Snjl acpi_tz_switch_cooler_off, sc); 49878915Smsmith 499119529Snjl /* Turn on cooling devices that are required, if any are */ 500119529Snjl if (newactive != TZ_ACTIVE_NONE) { 501119529Snjl acpi_ForeachPackageObject( 502119529Snjl (ACPI_OBJECT *)sc->tz_zone.al[newactive].Pointer, 503119529Snjl acpi_tz_switch_cooler_on, sc); 504119529Snjl } 50586552Siwasaki ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 506119529Snjl "switched from %s to %s: %d.%dC\n", 507119529Snjl acpi_tz_aclevel_string(sc->tz_active), 508119529Snjl acpi_tz_aclevel_string(newactive), TZ_KELVTOC(temp)); 50979283Smsmith sc->tz_active = newactive; 510142195Snjl getnanotime(&sc->tz_cooling_started); 51179283Smsmith } 51278915Smsmith 513119529Snjl /* XXX (de)activate any passive cooling that may be required. */ 51478915Smsmith 51578915Smsmith /* 516125335Snjl * If the temperature is at _HOT or _CRT, increment our event count. 517125335Snjl * If it has occurred enough times, shutdown the system. This is 518125335Snjl * needed because some systems will report an invalid high temperature 519125335Snjl * for one poll cycle. It is suspected this is due to the embedded 520125335Snjl * controller timing out. A typical value is 138C for one cycle on 521125335Snjl * a system that is otherwise 65C. 522125366Snjl * 523125366Snjl * If we're almost at that threshold, notify the user through devd(8). 52478915Smsmith */ 525125335Snjl if ((newflags & (TZ_THFLAG_HOT | TZ_THFLAG_CRT)) != 0) { 526125366Snjl sc->tz_validchecks++; 527125366Snjl if (sc->tz_validchecks == TZ_VALIDCHECKS) { 528125335Snjl device_printf(sc->tz_dev, 529125335Snjl "WARNING - current temperature (%d.%dC) exceeds safe limits\n", 530125335Snjl TZ_KELVTOC(sc->tz_temperature)); 531125335Snjl shutdown_nice(RB_POWEROFF); 532125366Snjl } else if (sc->tz_validchecks == TZ_NOTIFYCOUNT) 533125366Snjl acpi_UserNotify("Thermal", sc->tz_handle, TZ_NOTIFY_CRITICAL); 534125335Snjl } else { 535125335Snjl sc->tz_validchecks = 0; 53678915Smsmith } 53779375Smsmith sc->tz_thflags = newflags; 53878915Smsmith 53971874Smsmith return_VOID; 54071874Smsmith} 54170271Stakawata 54278915Smsmith/* 543148138Sume * Given an object, verify that it's a reference to a device of some sort, 54478915Smsmith * and try to switch it off. 54578915Smsmith */ 54678915Smsmithstatic void 54778915Smsmithacpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg) 54878915Smsmith{ 549128047Snjl ACPI_HANDLE cooler; 55078915Smsmith 55196926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 55278915Smsmith 553128047Snjl cooler = acpi_GetReference(NULL, obj); 554128047Snjl if (cooler == NULL) { 555128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get handle\n")); 556128047Snjl return_VOID; 557128047Snjl } 558102470Siwasaki 559128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s off\n", 560128047Snjl acpi_name(cooler))); 561128150Snjl acpi_pwr_switch_consumer(cooler, ACPI_STATE_D3); 562119529Snjl 56379375Smsmith return_VOID; 56478915Smsmith} 56578915Smsmith 56678915Smsmith/* 567148138Sume * Given an object, verify that it's a reference to a device of some sort, 56878915Smsmith * and try to switch it on. 56978915Smsmith * 570128047Snjl * XXX replication of off/on function code is bad. 57178915Smsmith */ 57278915Smsmithstatic void 57378915Smsmithacpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg) 57478915Smsmith{ 57578915Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg; 57678999Smsmith ACPI_HANDLE cooler; 57779375Smsmith ACPI_STATUS status; 578148138Sume 57996926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 58078915Smsmith 581128047Snjl cooler = acpi_GetReference(NULL, obj); 582128047Snjl if (cooler == NULL) { 583128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get handle\n")); 584128047Snjl return_VOID; 585128047Snjl } 586102470Siwasaki 587128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s on\n", 588128047Snjl acpi_name(cooler))); 589128047Snjl status = acpi_pwr_switch_consumer(cooler, ACPI_STATE_D0); 590128047Snjl if (ACPI_FAILURE(status)) { 591128047Snjl ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 592128047Snjl "failed to activate %s - %s\n", acpi_name(cooler), 593128047Snjl AcpiFormatException(status)); 59478915Smsmith } 595119529Snjl 596119529Snjl return_VOID; 59778915Smsmith} 59878915Smsmith 59978915Smsmith/* 60078915Smsmith * Read/debug-print a parameter, default it to -1. 60178915Smsmith */ 60278915Smsmithstatic void 60378915Smsmithacpi_tz_getparam(struct acpi_tz_softc *sc, char *node, int *data) 60478915Smsmith{ 60578915Smsmith 60696926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 60778915Smsmith 608126560Snjl if (ACPI_FAILURE(acpi_GetInteger(sc->tz_handle, node, data))) { 60978915Smsmith *data = -1; 61078915Smsmith } else { 611119529Snjl ACPI_DEBUG_PRINT((ACPI_DB_VALUES, "%s.%s = %d\n", 612119529Snjl acpi_name(sc->tz_handle), node, *data)); 61378915Smsmith } 614119529Snjl 615148138Sume return_VOID; 61678915Smsmith} 61779283Smsmith 61879283Smsmith/* 61979283Smsmith * Sanity-check a temperature value. Assume that setpoints 62079283Smsmith * should be between 0C and 150C. 62179283Smsmith */ 62279283Smsmithstatic void 62379283Smsmithacpi_tz_sanity(struct acpi_tz_softc *sc, int *val, char *what) 62479283Smsmith{ 625119529Snjl if (*val != -1 && (*val < TZ_ZEROC || *val > TZ_ZEROC + 1500)) { 62679283Smsmith device_printf(sc->tz_dev, "%s value is absurd, ignored (%d.%dC)\n", 62779283Smsmith what, TZ_KELVTOC(*val)); 62879283Smsmith *val = -1; 62979283Smsmith } 63079283Smsmith} 63179375Smsmith 63279375Smsmith/* 63379375Smsmith * Respond to a sysctl on the active state node. 634148138Sume */ 63579375Smsmithstatic int 63679375Smsmithacpi_tz_active_sysctl(SYSCTL_HANDLER_ARGS) 63779375Smsmith{ 63879375Smsmith struct acpi_tz_softc *sc; 63979375Smsmith int active; 64079375Smsmith int error; 64179375Smsmith 64279375Smsmith sc = (struct acpi_tz_softc *)oidp->oid_arg1; 64379375Smsmith active = sc->tz_active; 64479375Smsmith error = sysctl_handle_int(oidp, &active, 0, req); 64579375Smsmith 646119529Snjl /* Error or no new value */ 647119529Snjl if (error != 0 || req->newptr == NULL) 648133624Snjl return (error); 649133624Snjl if (active < -1 || active >= TZ_NUMLEVELS) 650133624Snjl return (EINVAL); 65179375Smsmith 652119529Snjl /* Set new preferred level and re-switch */ 65379375Smsmith sc->tz_requested = active; 654133624Snjl acpi_tz_signal(sc, 0); 655133624Snjl return (0); 65679375Smsmith} 65779375Smsmith 658148138Sumestatic int 659148138Sumeacpi_tz_cooling_sysctl(SYSCTL_HANDLER_ARGS) 660148138Sume{ 661148138Sume struct acpi_tz_softc *sc; 662148138Sume int enabled, error; 663148138Sume 664148138Sume sc = (struct acpi_tz_softc *)oidp->oid_arg1; 665148138Sume enabled = sc->tz_cooling_enabled; 666148138Sume error = sysctl_handle_int(oidp, &enabled, 0, req); 667148138Sume 668148138Sume /* Error or no new value */ 669148138Sume if (error != 0 || req->newptr == NULL) 670148138Sume return (error); 671148138Sume if (enabled != TRUE && enabled != FALSE) 672148138Sume return (EINVAL); 673148138Sume 674148138Sume if (enabled) { 675148138Sume if (acpi_tz_cooling_is_available(sc)) 676148138Sume error = acpi_tz_cooling_thread_start(sc); 677148138Sume else 678148138Sume error = ENODEV; 679148138Sume if (error) 680148138Sume enabled = FALSE; 681148138Sume } 682148138Sume sc->tz_cooling_enabled = enabled; 683148138Sume return (error); 684148138Sume} 685148138Sume 68678915Smsmithstatic void 68771874Smsmithacpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context) 68871874Smsmith{ 68978915Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)context; 69078915Smsmith 69196926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 69270271Stakawata 693133624Snjl switch (notify) { 69478915Smsmith case TZ_NOTIFY_TEMPERATURE: 695119529Snjl /* Temperature change occurred */ 696133624Snjl acpi_tz_signal(sc, 0); 69778915Smsmith break; 69878915Smsmith case TZ_NOTIFY_DEVICES: 69978915Smsmith case TZ_NOTIFY_LEVELS: 700119529Snjl /* Zone devices/setpoints changed */ 701133624Snjl acpi_tz_signal(sc, TZ_FLAG_GETSETTINGS); 70278915Smsmith break; 70378915Smsmith default: 70486552Siwasaki ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 705119529Snjl "unknown Notify event 0x%x\n", notify); 70678915Smsmith break; 70771874Smsmith } 708119529Snjl 709121493Snjl acpi_UserNotify("Thermal", h, notify); 710121493Snjl 71171874Smsmith return_VOID; 71271874Smsmith} 71370271Stakawata 714133624Snjlstatic void 715133624Snjlacpi_tz_signal(struct acpi_tz_softc *sc, int flags) 716133624Snjl{ 717133624Snjl ACPI_LOCK(thermal); 718133624Snjl sc->tz_flags |= flags; 719133624Snjl ACPI_UNLOCK(thermal); 720133624Snjl wakeup(&acpi_tz_proc); 721133624Snjl} 722133624Snjl 72378915Smsmith/* 724134909Snjl * Notifies can be generated asynchronously but have also been seen to be 725134909Snjl * triggered by other thermal methods. One system generates a notify of 726134909Snjl * 0x81 when the fan is turned on or off. Another generates it when _SCP 727134909Snjl * is called. To handle these situations, we check the zone via 728134909Snjl * acpi_tz_monitor() before evaluating changes to setpoints or the cooling 729134909Snjl * policy. 73078915Smsmith */ 73178915Smsmithstatic void 732133624Snjlacpi_tz_timeout(struct acpi_tz_softc *sc, int flags) 73378915Smsmith{ 734134909Snjl 735134909Snjl /* Check the current temperature and take action based on it */ 736134909Snjl acpi_tz_monitor(sc); 737134909Snjl 738133624Snjl /* If requested, get the power profile settings. */ 739133624Snjl if (flags & TZ_FLAG_GETPROFILE) 740133624Snjl acpi_tz_power_profile(sc); 74179375Smsmith 742134909Snjl /* 743134909Snjl * If requested, check for new devices/setpoints. After finding them, 744134909Snjl * check if we need to switch fans based on the new values. 745134909Snjl */ 746134909Snjl if (flags & TZ_FLAG_GETSETTINGS) { 747133624Snjl acpi_tz_establish(sc); 748134909Snjl acpi_tz_monitor(sc); 749134909Snjl } 75078915Smsmith 75178915Smsmith /* XXX passive cooling actions? */ 75278915Smsmith} 75379375Smsmith 75479375Smsmith/* 75579375Smsmith * System power profile may have changed; fetch and notify the 75679375Smsmith * thermal zone accordingly. 75779375Smsmith * 75879375Smsmith * Since this can be called from an arbitrary eventhandler, it needs 75979375Smsmith * to get the ACPI lock itself. 76079375Smsmith */ 76179375Smsmithstatic void 76291640Siwasakiacpi_tz_power_profile(void *arg) 76379375Smsmith{ 76479375Smsmith ACPI_STATUS status; 76579375Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg; 76691640Siwasaki int state; 76779375Smsmith 76891640Siwasaki state = power_profile_get_state(); 769119529Snjl if (state != POWER_PROFILE_PERFORMANCE && state != POWER_PROFILE_ECONOMY) 770119529Snjl return; 77191640Siwasaki 77279375Smsmith /* check that we haven't decided there's no _SCP method */ 773119529Snjl if ((sc->tz_flags & TZ_FLAG_NO_SCP) == 0) { 77479375Smsmith 775119529Snjl /* Call _SCP to set the new profile */ 776148138Sume status = acpi_SetInteger(sc->tz_handle, "_SCP", 777126560Snjl (state == POWER_PROFILE_PERFORMANCE) ? 0 : 1); 778119529Snjl if (ACPI_FAILURE(status)) { 77979385Smsmith if (status != AE_NOT_FOUND) 780119529Snjl ACPI_VPRINT(sc->tz_dev, 781119529Snjl acpi_device_get_parent_softc(sc->tz_dev), 782119529Snjl "can't evaluate %s._SCP - %s\n", 783119529Snjl acpi_name(sc->tz_handle), 784119529Snjl AcpiFormatException(status)); 78579375Smsmith sc->tz_flags |= TZ_FLAG_NO_SCP; 78679375Smsmith } else { 787119529Snjl /* We have to re-evaluate the entire zone now */ 788133624Snjl acpi_tz_signal(sc, TZ_FLAG_GETSETTINGS); 78979375Smsmith } 79079375Smsmith } 79179375Smsmith} 79279375Smsmith 79391126Smsmith/* 79491126Smsmith * Thermal zone monitor thread. 79591126Smsmith */ 79691126Smsmithstatic void 79791126Smsmithacpi_tz_thread(void *arg) 79891126Smsmith{ 79991126Smsmith device_t *devs; 80091126Smsmith int devcount, i; 801133624Snjl int flags; 802133624Snjl struct acpi_tz_softc **sc; 80391126Smsmith 80496926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 80591126Smsmith 80691126Smsmith devs = NULL; 80791126Smsmith devcount = 0; 808133624Snjl sc = NULL; 80991126Smsmith 81091126Smsmith for (;;) { 811133624Snjl /* If the number of devices has changed, re-evaluate. */ 812133624Snjl if (devclass_get_maxunit(acpi_tz_devclass) != devcount) { 813133624Snjl if (devs != NULL) { 814133624Snjl free(devs, M_TEMP); 815133624Snjl free(sc, M_TEMP); 816133624Snjl } 817133624Snjl devclass_get_devices(acpi_tz_devclass, &devs, &devcount); 818133624Snjl sc = malloc(sizeof(struct acpi_tz_softc *) * devcount, M_TEMP, 819133624Snjl M_WAITOK | M_ZERO); 820133624Snjl for (i = 0; i < devcount; i++) 821133624Snjl sc[i] = device_get_softc(devs[i]); 822133624Snjl } 82391126Smsmith 824133624Snjl /* Check for temperature events and act on them. */ 825133624Snjl for (i = 0; i < devcount; i++) { 826133624Snjl ACPI_LOCK(thermal); 827133624Snjl flags = sc[i]->tz_flags; 828133624Snjl sc[i]->tz_flags &= TZ_FLAG_NO_SCP; 829133624Snjl ACPI_UNLOCK(thermal); 830133624Snjl acpi_tz_timeout(sc[i], flags); 831133624Snjl } 83291215Smsmith 833133624Snjl /* If more work to do, don't go to sleep yet. */ 834133624Snjl ACPI_LOCK(thermal); 835133624Snjl for (i = 0; i < devcount; i++) { 836133624Snjl if (sc[i]->tz_flags & ~TZ_FLAG_NO_SCP) 837133624Snjl break; 838133624Snjl } 83991126Smsmith 840133624Snjl /* 841133624Snjl * If we have no more work, sleep for a while, setting PDROP so that 842133624Snjl * the mutex will not be reacquired. Otherwise, drop the mutex and 843133624Snjl * loop to handle more events. 844133624Snjl */ 845133624Snjl if (i == devcount) 846133624Snjl msleep(&acpi_tz_proc, &thermal_mutex, PZERO | PDROP, "tzpoll", 847133624Snjl hz * acpi_tz_polling_rate); 848133624Snjl else 849133624Snjl ACPI_UNLOCK(thermal); 85091126Smsmith } 85191126Smsmith} 852148138Sume 853148138Sumestatic int 854148138Sumeacpi_tz_cpufreq_restore(struct acpi_tz_softc *sc) 855148138Sume{ 856148138Sume device_t dev; 857148138Sume int error; 858148138Sume 859148138Sume if (!sc->tz_cooling_updated) 860148138Sume return (0); 861148138Sume if ((dev = devclass_get_device(devclass_find("cpufreq"), 0)) == NULL) 862148138Sume return (ENXIO); 863148138Sume ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 864149201Sume "temperature %d.%dC: resuming previous clock speed (%d MHz)\n", 865149201Sume TZ_KELVTOC(sc->tz_temperature), sc->tz_cooling_saved_freq); 866148138Sume error = CPUFREQ_SET(dev, NULL, CPUFREQ_PRIO_KERN); 867148138Sume if (error == 0) 868148138Sume sc->tz_cooling_updated = FALSE; 869148138Sume return (error); 870148138Sume} 871148138Sume 872148138Sumestatic int 873148138Sumeacpi_tz_cpufreq_update(struct acpi_tz_softc *sc, int req) 874148138Sume{ 875148138Sume device_t dev; 876148138Sume struct cf_level *levels; 877148138Sume int num_levels, error, freq, desired_freq, perf, i; 878148138Sume 879148138Sume levels = malloc(CPUFREQ_MAX_LEVELS * sizeof(*levels), M_TEMP, M_NOWAIT); 880148138Sume if (levels == NULL) 881148138Sume return (ENOMEM); 882148138Sume 883148138Sume /* 884148138Sume * Find the main device, cpufreq0. We don't yet support independent 885148138Sume * CPU frequency control on SMP. 886148138Sume */ 887148138Sume if ((dev = devclass_get_device(devclass_find("cpufreq"), 0)) == NULL) { 888148138Sume error = ENXIO; 889148138Sume goto out; 890148138Sume } 891148138Sume 892148138Sume /* Get the current frequency. */ 893148138Sume error = CPUFREQ_GET(dev, &levels[0]); 894148138Sume if (error) 895148138Sume goto out; 896148138Sume freq = levels[0].total_set.freq; 897148138Sume 898148138Sume /* Get the current available frequency levels. */ 899148138Sume num_levels = CPUFREQ_MAX_LEVELS; 900148138Sume error = CPUFREQ_LEVELS(dev, levels, &num_levels); 901148138Sume if (error) { 902148138Sume if (error == E2BIG) 903148138Sume printf("cpufreq: need to increase CPUFREQ_MAX_LEVELS\n"); 904148138Sume goto out; 905148138Sume } 906148138Sume 907148138Sume /* Calculate the desired frequency as a percent of the max frequency. */ 908148138Sume perf = 100 * freq / levels[0].total_set.freq - req; 909148138Sume if (perf < 0) 910148138Sume perf = 0; 911148138Sume else if (perf > 100) 912148138Sume perf = 100; 913148138Sume desired_freq = levels[0].total_set.freq * perf / 100; 914148138Sume 915149201Sume if (desired_freq < freq) { 916148138Sume /* Find the closest available frequency, rounding down. */ 917148138Sume for (i = 0; i < num_levels; i++) 918148138Sume if (levels[i].total_set.freq <= desired_freq) 919148138Sume break; 920148138Sume 921148138Sume /* If we didn't find a relevant setting, use the lowest. */ 922148138Sume if (i == num_levels) 923148138Sume i--; 924148138Sume } else { 925149201Sume /* If we didn't decrease frequency yet, don't increase it. */ 926149201Sume if (!sc->tz_cooling_updated) { 927149201Sume sc->tz_cooling_active = FALSE; 928149201Sume goto out; 929149201Sume } 930149201Sume 931149201Sume /* Use saved cpu frequency as maximum value. */ 932149201Sume if (desired_freq > sc->tz_cooling_saved_freq) 933149201Sume desired_freq = sc->tz_cooling_saved_freq; 934149201Sume 935148138Sume /* Find the closest available frequency, rounding up. */ 936148138Sume for (i = num_levels - 1; i >= 0; i--) 937148138Sume if (levels[i].total_set.freq >= desired_freq) 938148138Sume break; 939148138Sume 940148138Sume /* If we didn't find a relevant setting, use the highest. */ 941148138Sume if (i == -1) 942148138Sume i++; 943148138Sume 944149201Sume /* If we're going to the highest frequency, restore the old setting. */ 945149201Sume if (i == 0 || desired_freq == sc->tz_cooling_saved_freq) { 946149201Sume error = acpi_tz_cpufreq_restore(sc); 947149201Sume if (error == 0) 948149201Sume sc->tz_cooling_active = FALSE; 949149201Sume goto out; 950149201Sume } 951148138Sume } 952148138Sume 953148138Sume /* If we are going to a new frequency, activate it. */ 954148138Sume if (levels[i].total_set.freq != freq) { 955148138Sume ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 956148138Sume "temperature %d.%dC: %screasing clock speed " 957148138Sume "from %d MHz to %d MHz\n", 958148138Sume TZ_KELVTOC(sc->tz_temperature), 959148138Sume (freq > levels[i].total_set.freq) ? "de" : "in", 960148138Sume freq, levels[i].total_set.freq); 961148138Sume error = CPUFREQ_SET(dev, &levels[i], CPUFREQ_PRIO_KERN); 962149201Sume if (error == 0 && !sc->tz_cooling_updated) { 963149201Sume sc->tz_cooling_saved_freq = freq; 964148138Sume sc->tz_cooling_updated = TRUE; 965149201Sume } 966148138Sume } 967148138Sume 968148138Sumeout: 969148138Sume if (levels) 970148138Sume free(levels, M_TEMP); 971148138Sume return (error); 972148138Sume} 973148138Sume 974148138Sume/* 975148138Sume * Passive cooling thread; monitors current temperature according to the 976148138Sume * cooling interval and calculates whether to scale back CPU frequency. 977148138Sume */ 978148138Sumestatic void 979148138Sumeacpi_tz_cooling_thread(void *arg) 980148138Sume{ 981148138Sume struct acpi_tz_softc *sc; 982148138Sume int error, perf, temperature; 983148138Sume 984148138Sume ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 985148138Sume 986148138Sume sc = (struct acpi_tz_softc *)arg; 987148138Sume 988148138Sume temperature = sc->tz_temperature; 989148138Sume while (sc->tz_cooling_enabled) { 990148138Sume if (sc->tz_temperature >= sc->tz_zone.psv) 991148138Sume sc->tz_cooling_active = TRUE; 992148138Sume if (sc->tz_cooling_active) { 993148138Sume perf = sc->tz_zone.tc1 * (sc->tz_temperature - temperature) + 994148138Sume sc->tz_zone.tc2 * (sc->tz_temperature - sc->tz_zone.psv); 995148138Sume perf /= 10; 996148138Sume 997148138Sume if (perf != 0) { 998148138Sume error = acpi_tz_cpufreq_update(sc, perf); 999148138Sume 1000148138Sume /* 1001148138Sume * If error and not simply a higher priority setting was 1002148138Sume * active, disable cooling. 1003148138Sume */ 1004148138Sume if (error != 0 && error != EPERM) { 1005148138Sume device_printf(sc->tz_dev, 1006148138Sume "failed to set new freq, disabling passive cooling\n"); 1007148138Sume sc->tz_cooling_enabled = FALSE; 1008148138Sume } 1009148138Sume } 1010148138Sume } 1011148138Sume temperature = sc->tz_temperature; 1012148138Sume tsleep(&sc->tz_cooling_proc, PZERO, "cooling", 1013148138Sume hz * sc->tz_zone.tsp / 10); 1014148138Sume } 1015148138Sume if (sc->tz_cooling_active) { 1016148138Sume acpi_tz_cpufreq_restore(sc); 1017148138Sume sc->tz_cooling_active = FALSE; 1018148138Sume } 1019148703Sume sc->tz_cooling_proc = NULL; 1020148138Sume ACPI_LOCK(thermal); 1021148703Sume sc->tz_cooling_proc_running = FALSE; 1022148138Sume ACPI_UNLOCK(thermal); 1023148138Sume kthread_exit(0); 1024148138Sume} 1025148138Sume 1026148138Sume/* 1027148138Sume * TODO: We ignore _PSL (list of cooling devices) since cpufreq enumerates 1028148138Sume * all CPUs for us. However, it's possible in the future _PSL will 1029148138Sume * reference non-CPU devices so we may want to support it then. 1030148138Sume */ 1031148138Sumestatic int 1032148138Sumeacpi_tz_cooling_is_available(struct acpi_tz_softc *sc) 1033148138Sume{ 1034148138Sume return (sc->tz_zone.tc1 != -1 && sc->tz_zone.tc2 != -1 && 1035148138Sume sc->tz_zone.tsp != -1 && sc->tz_zone.tsp != 0 && 1036148138Sume sc->tz_zone.psv != -1); 1037148138Sume} 1038148138Sume 1039148138Sumestatic int 1040148138Sumeacpi_tz_cooling_thread_start(struct acpi_tz_softc *sc) 1041148138Sume{ 1042148138Sume int error; 1043148138Sume char name[16]; 1044148138Sume 1045148703Sume ACPI_LOCK(thermal); 1046148703Sume if (sc->tz_cooling_proc_running) { 1047148703Sume ACPI_UNLOCK(thermal); 1048148703Sume return (0); 1049148703Sume } 1050148703Sume sc->tz_cooling_proc_running = TRUE; 1051148703Sume ACPI_UNLOCK(thermal); 1052148138Sume error = 0; 1053148138Sume if (sc->tz_cooling_proc == NULL) { 1054148138Sume snprintf(name, sizeof(name), "acpi_cooling%d", 1055148138Sume device_get_unit(sc->tz_dev)); 1056148138Sume error = kthread_create(acpi_tz_cooling_thread, sc, 1057148138Sume &sc->tz_cooling_proc, RFHIGHPID, 0, name); 1058148703Sume if (error != 0) { 1059148138Sume device_printf(sc->tz_dev, "could not create thread - %d", error); 1060148703Sume ACPI_LOCK(thermal); 1061148703Sume sc->tz_cooling_proc_running = FALSE; 1062148703Sume ACPI_UNLOCK(thermal); 1063148703Sume } 1064148138Sume } 1065148138Sume return (error); 1066148138Sume} 1067