acpi_thermal.c revision 149450
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 149450 2005-08-25 11:31:30Z 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/* 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 426149450Sume status = acpi_GetInteger(sc->tz_handle, "_TMP", &temp); 427149450Sume if (ACPI_FAILURE(status)) { 428149450Sume ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 429149450Sume "error fetching current temperature -- %s\n", 430149450Sume AcpiFormatException(status)); 431149450Sume return (FALSE); 432149450Sume } 433149450Sume 434149450Sume ACPI_DEBUG_PRINT((ACPI_DB_VALUES, "got %d.%dC\n", TZ_KELVTOC(temp))); 435149450Sume sc->tz_temperature = temp; 436149450Sume return (TRUE); 437149450Sume} 438149450Sume 439149450Sume/* 44078915Smsmith * Evaluate the condition of a thermal zone, take appropriate actions. 44178915Smsmith */ 44271874Smsmithstatic void 443119529Snjlacpi_tz_monitor(void *Context) 44471874Smsmith{ 445119529Snjl struct acpi_tz_softc *sc; 446119529Snjl struct timespec curtime; 44779283Smsmith int temp; 44878915Smsmith int i; 44979283Smsmith int newactive, newflags; 45070271Stakawata 45196926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 45270271Stakawata 453119529Snjl sc = (struct acpi_tz_softc *)Context; 45488420Siwasaki 455119529Snjl /* Get the current temperature. */ 456149450Sume if (!acpi_tz_get_temperature(sc)) { 45778915Smsmith /* XXX disable zone? go to max cooling? */ 458133624Snjl return_VOID; 45971874Smsmith } 460149450Sume temp = sc->tz_temperature; 46188420Siwasaki 46278915Smsmith /* 46378915Smsmith * Work out what we ought to be doing right now. 46479283Smsmith * 46579283Smsmith * Note that the _ACx levels sort from hot to cold. 46678915Smsmith */ 46779283Smsmith newactive = TZ_ACTIVE_NONE; 46879375Smsmith for (i = TZ_NUMLEVELS - 1; i >= 0; i--) { 469142195Snjl if (sc->tz_zone.ac[i] != -1 && temp >= sc->tz_zone.ac[i]) { 47079283Smsmith newactive = i; 47182967Siwasaki if (sc->tz_active != newactive) { 472119529Snjl ACPI_VPRINT(sc->tz_dev, 473119529Snjl acpi_device_get_parent_softc(sc->tz_dev), 474119529Snjl "_AC%d: temperature %d.%d >= setpoint %d.%d\n", i, 475119529Snjl TZ_KELVTOC(temp), TZ_KELVTOC(sc->tz_zone.ac[i])); 47682967Siwasaki } 47779375Smsmith } 47879375Smsmith } 47979283Smsmith 48085699Siwasaki /* 48185699Siwasaki * We are going to get _ACx level down (colder side), but give a guaranteed 48285699Siwasaki * minimum cooling run time if requested. 48385699Siwasaki */ 48485699Siwasaki if (acpi_tz_min_runtime > 0 && sc->tz_active != TZ_ACTIVE_NONE && 48585699Siwasaki (newactive == TZ_ACTIVE_NONE || newactive > sc->tz_active)) { 486119529Snjl 48785699Siwasaki getnanotime(&curtime); 48885699Siwasaki timespecsub(&curtime, &sc->tz_cooling_started); 489119529Snjl if (curtime.tv_sec < acpi_tz_min_runtime) 49085699Siwasaki newactive = sc->tz_active; 49185699Siwasaki } 49285699Siwasaki 493119529Snjl /* Handle user override of active mode */ 494126662Snjl if (sc->tz_requested != TZ_ACTIVE_NONE && sc->tz_requested < newactive) 49579375Smsmith newactive = sc->tz_requested; 49678915Smsmith 49779375Smsmith /* update temperature-related flags */ 49879375Smsmith newflags = TZ_THFLAG_NONE; 499124439Snjl if (sc->tz_zone.psv != -1 && temp >= sc->tz_zone.psv) 50079375Smsmith newflags |= TZ_THFLAG_PSV; 501124439Snjl if (sc->tz_zone.hot != -1 && temp >= sc->tz_zone.hot) 50279375Smsmith newflags |= TZ_THFLAG_HOT; 503124439Snjl if (sc->tz_zone.crt != -1 && temp >= sc->tz_zone.crt) 50479375Smsmith newflags |= TZ_THFLAG_CRT; 50579375Smsmith 506119529Snjl /* If the active cooling state has changed, we have to switch things. */ 50779283Smsmith if (newactive != sc->tz_active) { 508119529Snjl /* Turn off the cooling devices that are on, if any are */ 50979283Smsmith if (sc->tz_active != TZ_ACTIVE_NONE) 510119529Snjl acpi_ForeachPackageObject( 511119529Snjl (ACPI_OBJECT *)sc->tz_zone.al[sc->tz_active].Pointer, 512119529Snjl acpi_tz_switch_cooler_off, sc); 51378915Smsmith 514119529Snjl /* Turn on cooling devices that are required, if any are */ 515119529Snjl if (newactive != TZ_ACTIVE_NONE) { 516119529Snjl acpi_ForeachPackageObject( 517119529Snjl (ACPI_OBJECT *)sc->tz_zone.al[newactive].Pointer, 518119529Snjl acpi_tz_switch_cooler_on, sc); 519119529Snjl } 52086552Siwasaki ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 521119529Snjl "switched from %s to %s: %d.%dC\n", 522119529Snjl acpi_tz_aclevel_string(sc->tz_active), 523119529Snjl acpi_tz_aclevel_string(newactive), TZ_KELVTOC(temp)); 52479283Smsmith sc->tz_active = newactive; 525142195Snjl getnanotime(&sc->tz_cooling_started); 52679283Smsmith } 52778915Smsmith 528119529Snjl /* XXX (de)activate any passive cooling that may be required. */ 52978915Smsmith 53078915Smsmith /* 531125335Snjl * If the temperature is at _HOT or _CRT, increment our event count. 532125335Snjl * If it has occurred enough times, shutdown the system. This is 533125335Snjl * needed because some systems will report an invalid high temperature 534125335Snjl * for one poll cycle. It is suspected this is due to the embedded 535125335Snjl * controller timing out. A typical value is 138C for one cycle on 536125335Snjl * a system that is otherwise 65C. 537125366Snjl * 538125366Snjl * If we're almost at that threshold, notify the user through devd(8). 53978915Smsmith */ 540125335Snjl if ((newflags & (TZ_THFLAG_HOT | TZ_THFLAG_CRT)) != 0) { 541125366Snjl sc->tz_validchecks++; 542125366Snjl if (sc->tz_validchecks == TZ_VALIDCHECKS) { 543125335Snjl device_printf(sc->tz_dev, 544125335Snjl "WARNING - current temperature (%d.%dC) exceeds safe limits\n", 545125335Snjl TZ_KELVTOC(sc->tz_temperature)); 546125335Snjl shutdown_nice(RB_POWEROFF); 547125366Snjl } else if (sc->tz_validchecks == TZ_NOTIFYCOUNT) 548125366Snjl acpi_UserNotify("Thermal", sc->tz_handle, TZ_NOTIFY_CRITICAL); 549125335Snjl } else { 550125335Snjl sc->tz_validchecks = 0; 55178915Smsmith } 55279375Smsmith sc->tz_thflags = newflags; 55378915Smsmith 55471874Smsmith return_VOID; 55571874Smsmith} 55670271Stakawata 55778915Smsmith/* 558148138Sume * Given an object, verify that it's a reference to a device of some sort, 55978915Smsmith * and try to switch it off. 56078915Smsmith */ 56178915Smsmithstatic void 56278915Smsmithacpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg) 56378915Smsmith{ 564128047Snjl ACPI_HANDLE cooler; 56578915Smsmith 56696926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 56778915Smsmith 568128047Snjl cooler = acpi_GetReference(NULL, obj); 569128047Snjl if (cooler == NULL) { 570128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get handle\n")); 571128047Snjl return_VOID; 572128047Snjl } 573102470Siwasaki 574128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s off\n", 575128047Snjl acpi_name(cooler))); 576128150Snjl acpi_pwr_switch_consumer(cooler, ACPI_STATE_D3); 577119529Snjl 57879375Smsmith return_VOID; 57978915Smsmith} 58078915Smsmith 58178915Smsmith/* 582148138Sume * Given an object, verify that it's a reference to a device of some sort, 58378915Smsmith * and try to switch it on. 58478915Smsmith * 585128047Snjl * XXX replication of off/on function code is bad. 58678915Smsmith */ 58778915Smsmithstatic void 58878915Smsmithacpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg) 58978915Smsmith{ 59078915Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg; 59178999Smsmith ACPI_HANDLE cooler; 59279375Smsmith ACPI_STATUS status; 593148138Sume 59496926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 59578915Smsmith 596128047Snjl cooler = acpi_GetReference(NULL, obj); 597128047Snjl if (cooler == NULL) { 598128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get handle\n")); 599128047Snjl return_VOID; 600128047Snjl } 601102470Siwasaki 602128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s on\n", 603128047Snjl acpi_name(cooler))); 604128047Snjl status = acpi_pwr_switch_consumer(cooler, ACPI_STATE_D0); 605128047Snjl if (ACPI_FAILURE(status)) { 606128047Snjl ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 607128047Snjl "failed to activate %s - %s\n", acpi_name(cooler), 608128047Snjl AcpiFormatException(status)); 60978915Smsmith } 610119529Snjl 611119529Snjl return_VOID; 61278915Smsmith} 61378915Smsmith 61478915Smsmith/* 61578915Smsmith * Read/debug-print a parameter, default it to -1. 61678915Smsmith */ 61778915Smsmithstatic void 61878915Smsmithacpi_tz_getparam(struct acpi_tz_softc *sc, char *node, int *data) 61978915Smsmith{ 62078915Smsmith 62196926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 62278915Smsmith 623126560Snjl if (ACPI_FAILURE(acpi_GetInteger(sc->tz_handle, node, data))) { 62478915Smsmith *data = -1; 62578915Smsmith } else { 626119529Snjl ACPI_DEBUG_PRINT((ACPI_DB_VALUES, "%s.%s = %d\n", 627119529Snjl acpi_name(sc->tz_handle), node, *data)); 62878915Smsmith } 629119529Snjl 630148138Sume return_VOID; 63178915Smsmith} 63279283Smsmith 63379283Smsmith/* 63479283Smsmith * Sanity-check a temperature value. Assume that setpoints 63579283Smsmith * should be between 0C and 150C. 63679283Smsmith */ 63779283Smsmithstatic void 63879283Smsmithacpi_tz_sanity(struct acpi_tz_softc *sc, int *val, char *what) 63979283Smsmith{ 640119529Snjl if (*val != -1 && (*val < TZ_ZEROC || *val > TZ_ZEROC + 1500)) { 64179283Smsmith device_printf(sc->tz_dev, "%s value is absurd, ignored (%d.%dC)\n", 64279283Smsmith what, TZ_KELVTOC(*val)); 64379283Smsmith *val = -1; 64479283Smsmith } 64579283Smsmith} 64679375Smsmith 64779375Smsmith/* 64879375Smsmith * Respond to a sysctl on the active state node. 649148138Sume */ 65079375Smsmithstatic int 65179375Smsmithacpi_tz_active_sysctl(SYSCTL_HANDLER_ARGS) 65279375Smsmith{ 65379375Smsmith struct acpi_tz_softc *sc; 65479375Smsmith int active; 65579375Smsmith int error; 65679375Smsmith 65779375Smsmith sc = (struct acpi_tz_softc *)oidp->oid_arg1; 65879375Smsmith active = sc->tz_active; 65979375Smsmith error = sysctl_handle_int(oidp, &active, 0, req); 66079375Smsmith 661119529Snjl /* Error or no new value */ 662119529Snjl if (error != 0 || req->newptr == NULL) 663133624Snjl return (error); 664133624Snjl if (active < -1 || active >= TZ_NUMLEVELS) 665133624Snjl return (EINVAL); 66679375Smsmith 667119529Snjl /* Set new preferred level and re-switch */ 66879375Smsmith sc->tz_requested = active; 669133624Snjl acpi_tz_signal(sc, 0); 670133624Snjl return (0); 67179375Smsmith} 67279375Smsmith 673148138Sumestatic int 674148138Sumeacpi_tz_cooling_sysctl(SYSCTL_HANDLER_ARGS) 675148138Sume{ 676148138Sume struct acpi_tz_softc *sc; 677148138Sume int enabled, error; 678148138Sume 679148138Sume sc = (struct acpi_tz_softc *)oidp->oid_arg1; 680148138Sume enabled = sc->tz_cooling_enabled; 681148138Sume error = sysctl_handle_int(oidp, &enabled, 0, req); 682148138Sume 683148138Sume /* Error or no new value */ 684148138Sume if (error != 0 || req->newptr == NULL) 685148138Sume return (error); 686148138Sume if (enabled != TRUE && enabled != FALSE) 687148138Sume return (EINVAL); 688148138Sume 689148138Sume if (enabled) { 690148138Sume if (acpi_tz_cooling_is_available(sc)) 691148138Sume error = acpi_tz_cooling_thread_start(sc); 692148138Sume else 693148138Sume error = ENODEV; 694148138Sume if (error) 695148138Sume enabled = FALSE; 696148138Sume } 697148138Sume sc->tz_cooling_enabled = enabled; 698148138Sume return (error); 699148138Sume} 700148138Sume 70178915Smsmithstatic void 70271874Smsmithacpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context) 70371874Smsmith{ 70478915Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)context; 70578915Smsmith 70696926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 70770271Stakawata 708133624Snjl switch (notify) { 70978915Smsmith case TZ_NOTIFY_TEMPERATURE: 710119529Snjl /* Temperature change occurred */ 711133624Snjl acpi_tz_signal(sc, 0); 71278915Smsmith break; 71378915Smsmith case TZ_NOTIFY_DEVICES: 71478915Smsmith case TZ_NOTIFY_LEVELS: 715119529Snjl /* Zone devices/setpoints changed */ 716133624Snjl acpi_tz_signal(sc, TZ_FLAG_GETSETTINGS); 71778915Smsmith break; 71878915Smsmith default: 71986552Siwasaki ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 720119529Snjl "unknown Notify event 0x%x\n", notify); 72178915Smsmith break; 72271874Smsmith } 723119529Snjl 724121493Snjl acpi_UserNotify("Thermal", h, notify); 725121493Snjl 72671874Smsmith return_VOID; 72771874Smsmith} 72870271Stakawata 729133624Snjlstatic void 730133624Snjlacpi_tz_signal(struct acpi_tz_softc *sc, int flags) 731133624Snjl{ 732133624Snjl ACPI_LOCK(thermal); 733133624Snjl sc->tz_flags |= flags; 734133624Snjl ACPI_UNLOCK(thermal); 735133624Snjl wakeup(&acpi_tz_proc); 736133624Snjl} 737133624Snjl 73878915Smsmith/* 739134909Snjl * Notifies can be generated asynchronously but have also been seen to be 740134909Snjl * triggered by other thermal methods. One system generates a notify of 741134909Snjl * 0x81 when the fan is turned on or off. Another generates it when _SCP 742134909Snjl * is called. To handle these situations, we check the zone via 743134909Snjl * acpi_tz_monitor() before evaluating changes to setpoints or the cooling 744134909Snjl * policy. 74578915Smsmith */ 74678915Smsmithstatic void 747133624Snjlacpi_tz_timeout(struct acpi_tz_softc *sc, int flags) 74878915Smsmith{ 749134909Snjl 750134909Snjl /* Check the current temperature and take action based on it */ 751134909Snjl acpi_tz_monitor(sc); 752134909Snjl 753133624Snjl /* If requested, get the power profile settings. */ 754133624Snjl if (flags & TZ_FLAG_GETPROFILE) 755133624Snjl acpi_tz_power_profile(sc); 75679375Smsmith 757134909Snjl /* 758134909Snjl * If requested, check for new devices/setpoints. After finding them, 759134909Snjl * check if we need to switch fans based on the new values. 760134909Snjl */ 761134909Snjl if (flags & TZ_FLAG_GETSETTINGS) { 762133624Snjl acpi_tz_establish(sc); 763134909Snjl acpi_tz_monitor(sc); 764134909Snjl } 76578915Smsmith 76678915Smsmith /* XXX passive cooling actions? */ 76778915Smsmith} 76879375Smsmith 76979375Smsmith/* 77079375Smsmith * System power profile may have changed; fetch and notify the 77179375Smsmith * thermal zone accordingly. 77279375Smsmith * 77379375Smsmith * Since this can be called from an arbitrary eventhandler, it needs 77479375Smsmith * to get the ACPI lock itself. 77579375Smsmith */ 77679375Smsmithstatic void 77791640Siwasakiacpi_tz_power_profile(void *arg) 77879375Smsmith{ 77979375Smsmith ACPI_STATUS status; 78079375Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg; 78191640Siwasaki int state; 78279375Smsmith 78391640Siwasaki state = power_profile_get_state(); 784119529Snjl if (state != POWER_PROFILE_PERFORMANCE && state != POWER_PROFILE_ECONOMY) 785119529Snjl return; 78691640Siwasaki 78779375Smsmith /* check that we haven't decided there's no _SCP method */ 788119529Snjl if ((sc->tz_flags & TZ_FLAG_NO_SCP) == 0) { 78979375Smsmith 790119529Snjl /* Call _SCP to set the new profile */ 791148138Sume status = acpi_SetInteger(sc->tz_handle, "_SCP", 792126560Snjl (state == POWER_PROFILE_PERFORMANCE) ? 0 : 1); 793119529Snjl if (ACPI_FAILURE(status)) { 79479385Smsmith if (status != AE_NOT_FOUND) 795119529Snjl ACPI_VPRINT(sc->tz_dev, 796119529Snjl acpi_device_get_parent_softc(sc->tz_dev), 797119529Snjl "can't evaluate %s._SCP - %s\n", 798119529Snjl acpi_name(sc->tz_handle), 799119529Snjl AcpiFormatException(status)); 80079375Smsmith sc->tz_flags |= TZ_FLAG_NO_SCP; 80179375Smsmith } else { 802119529Snjl /* We have to re-evaluate the entire zone now */ 803133624Snjl acpi_tz_signal(sc, TZ_FLAG_GETSETTINGS); 80479375Smsmith } 80579375Smsmith } 80679375Smsmith} 80779375Smsmith 80891126Smsmith/* 80991126Smsmith * Thermal zone monitor thread. 81091126Smsmith */ 81191126Smsmithstatic void 81291126Smsmithacpi_tz_thread(void *arg) 81391126Smsmith{ 81491126Smsmith device_t *devs; 81591126Smsmith int devcount, i; 816133624Snjl int flags; 817133624Snjl struct acpi_tz_softc **sc; 81891126Smsmith 81996926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 82091126Smsmith 82191126Smsmith devs = NULL; 82291126Smsmith devcount = 0; 823133624Snjl sc = NULL; 82491126Smsmith 82591126Smsmith for (;;) { 826133624Snjl /* If the number of devices has changed, re-evaluate. */ 827133624Snjl if (devclass_get_maxunit(acpi_tz_devclass) != devcount) { 828133624Snjl if (devs != NULL) { 829133624Snjl free(devs, M_TEMP); 830133624Snjl free(sc, M_TEMP); 831133624Snjl } 832133624Snjl devclass_get_devices(acpi_tz_devclass, &devs, &devcount); 833133624Snjl sc = malloc(sizeof(struct acpi_tz_softc *) * devcount, M_TEMP, 834133624Snjl M_WAITOK | M_ZERO); 835133624Snjl for (i = 0; i < devcount; i++) 836133624Snjl sc[i] = device_get_softc(devs[i]); 837133624Snjl } 83891126Smsmith 839133624Snjl /* Check for temperature events and act on them. */ 840133624Snjl for (i = 0; i < devcount; i++) { 841133624Snjl ACPI_LOCK(thermal); 842133624Snjl flags = sc[i]->tz_flags; 843133624Snjl sc[i]->tz_flags &= TZ_FLAG_NO_SCP; 844133624Snjl ACPI_UNLOCK(thermal); 845133624Snjl acpi_tz_timeout(sc[i], flags); 846133624Snjl } 84791215Smsmith 848133624Snjl /* If more work to do, don't go to sleep yet. */ 849133624Snjl ACPI_LOCK(thermal); 850133624Snjl for (i = 0; i < devcount; i++) { 851133624Snjl if (sc[i]->tz_flags & ~TZ_FLAG_NO_SCP) 852133624Snjl break; 853133624Snjl } 85491126Smsmith 855133624Snjl /* 856133624Snjl * If we have no more work, sleep for a while, setting PDROP so that 857133624Snjl * the mutex will not be reacquired. Otherwise, drop the mutex and 858133624Snjl * loop to handle more events. 859133624Snjl */ 860133624Snjl if (i == devcount) 861133624Snjl msleep(&acpi_tz_proc, &thermal_mutex, PZERO | PDROP, "tzpoll", 862133624Snjl hz * acpi_tz_polling_rate); 863133624Snjl else 864133624Snjl ACPI_UNLOCK(thermal); 86591126Smsmith } 86691126Smsmith} 867148138Sume 868148138Sumestatic int 869148138Sumeacpi_tz_cpufreq_restore(struct acpi_tz_softc *sc) 870148138Sume{ 871148138Sume device_t dev; 872148138Sume int error; 873148138Sume 874148138Sume if (!sc->tz_cooling_updated) 875148138Sume return (0); 876148138Sume if ((dev = devclass_get_device(devclass_find("cpufreq"), 0)) == NULL) 877148138Sume return (ENXIO); 878148138Sume ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 879149201Sume "temperature %d.%dC: resuming previous clock speed (%d MHz)\n", 880149201Sume TZ_KELVTOC(sc->tz_temperature), sc->tz_cooling_saved_freq); 881148138Sume error = CPUFREQ_SET(dev, NULL, CPUFREQ_PRIO_KERN); 882148138Sume if (error == 0) 883148138Sume sc->tz_cooling_updated = FALSE; 884148138Sume return (error); 885148138Sume} 886148138Sume 887148138Sumestatic int 888148138Sumeacpi_tz_cpufreq_update(struct acpi_tz_softc *sc, int req) 889148138Sume{ 890148138Sume device_t dev; 891148138Sume struct cf_level *levels; 892148138Sume int num_levels, error, freq, desired_freq, perf, i; 893148138Sume 894148138Sume levels = malloc(CPUFREQ_MAX_LEVELS * sizeof(*levels), M_TEMP, M_NOWAIT); 895148138Sume if (levels == NULL) 896148138Sume return (ENOMEM); 897148138Sume 898148138Sume /* 899148138Sume * Find the main device, cpufreq0. We don't yet support independent 900148138Sume * CPU frequency control on SMP. 901148138Sume */ 902148138Sume if ((dev = devclass_get_device(devclass_find("cpufreq"), 0)) == NULL) { 903148138Sume error = ENXIO; 904148138Sume goto out; 905148138Sume } 906148138Sume 907148138Sume /* Get the current frequency. */ 908148138Sume error = CPUFREQ_GET(dev, &levels[0]); 909148138Sume if (error) 910148138Sume goto out; 911148138Sume freq = levels[0].total_set.freq; 912148138Sume 913148138Sume /* Get the current available frequency levels. */ 914148138Sume num_levels = CPUFREQ_MAX_LEVELS; 915148138Sume error = CPUFREQ_LEVELS(dev, levels, &num_levels); 916148138Sume if (error) { 917148138Sume if (error == E2BIG) 918148138Sume printf("cpufreq: need to increase CPUFREQ_MAX_LEVELS\n"); 919148138Sume goto out; 920148138Sume } 921148138Sume 922148138Sume /* Calculate the desired frequency as a percent of the max frequency. */ 923148138Sume perf = 100 * freq / levels[0].total_set.freq - req; 924148138Sume if (perf < 0) 925148138Sume perf = 0; 926148138Sume else if (perf > 100) 927148138Sume perf = 100; 928148138Sume desired_freq = levels[0].total_set.freq * perf / 100; 929148138Sume 930149201Sume if (desired_freq < freq) { 931148138Sume /* Find the closest available frequency, rounding down. */ 932148138Sume for (i = 0; i < num_levels; i++) 933148138Sume if (levels[i].total_set.freq <= desired_freq) 934148138Sume break; 935148138Sume 936148138Sume /* If we didn't find a relevant setting, use the lowest. */ 937148138Sume if (i == num_levels) 938148138Sume i--; 939148138Sume } else { 940149201Sume /* If we didn't decrease frequency yet, don't increase it. */ 941149201Sume if (!sc->tz_cooling_updated) { 942149201Sume sc->tz_cooling_active = FALSE; 943149201Sume goto out; 944149201Sume } 945149201Sume 946149201Sume /* Use saved cpu frequency as maximum value. */ 947149201Sume if (desired_freq > sc->tz_cooling_saved_freq) 948149201Sume desired_freq = sc->tz_cooling_saved_freq; 949149201Sume 950148138Sume /* Find the closest available frequency, rounding up. */ 951148138Sume for (i = num_levels - 1; i >= 0; i--) 952148138Sume if (levels[i].total_set.freq >= desired_freq) 953148138Sume break; 954148138Sume 955148138Sume /* If we didn't find a relevant setting, use the highest. */ 956148138Sume if (i == -1) 957148138Sume i++; 958148138Sume 959149201Sume /* If we're going to the highest frequency, restore the old setting. */ 960149201Sume if (i == 0 || desired_freq == sc->tz_cooling_saved_freq) { 961149201Sume error = acpi_tz_cpufreq_restore(sc); 962149201Sume if (error == 0) 963149201Sume sc->tz_cooling_active = FALSE; 964149201Sume goto out; 965149201Sume } 966148138Sume } 967148138Sume 968148138Sume /* If we are going to a new frequency, activate it. */ 969148138Sume if (levels[i].total_set.freq != freq) { 970148138Sume ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 971148138Sume "temperature %d.%dC: %screasing clock speed " 972148138Sume "from %d MHz to %d MHz\n", 973148138Sume TZ_KELVTOC(sc->tz_temperature), 974148138Sume (freq > levels[i].total_set.freq) ? "de" : "in", 975148138Sume freq, levels[i].total_set.freq); 976148138Sume error = CPUFREQ_SET(dev, &levels[i], CPUFREQ_PRIO_KERN); 977149201Sume if (error == 0 && !sc->tz_cooling_updated) { 978149201Sume sc->tz_cooling_saved_freq = freq; 979148138Sume sc->tz_cooling_updated = TRUE; 980149201Sume } 981148138Sume } 982148138Sume 983148138Sumeout: 984148138Sume if (levels) 985148138Sume free(levels, M_TEMP); 986148138Sume return (error); 987148138Sume} 988148138Sume 989148138Sume/* 990148138Sume * Passive cooling thread; monitors current temperature according to the 991148138Sume * cooling interval and calculates whether to scale back CPU frequency. 992148138Sume */ 993148138Sumestatic void 994148138Sumeacpi_tz_cooling_thread(void *arg) 995148138Sume{ 996148138Sume struct acpi_tz_softc *sc; 997149450Sume int error, perf, curr_temp, prev_temp; 998148138Sume 999148138Sume ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 1000148138Sume 1001148138Sume sc = (struct acpi_tz_softc *)arg; 1002148138Sume 1003149450Sume prev_temp = sc->tz_temperature; 1004148138Sume while (sc->tz_cooling_enabled) { 1005149450Sume if (sc->tz_cooling_active) 1006149450Sume (void)acpi_tz_get_temperature(sc); 1007149450Sume curr_temp = sc->tz_temperature; 1008149450Sume if (curr_temp >= sc->tz_zone.psv) 1009148138Sume sc->tz_cooling_active = TRUE; 1010148138Sume if (sc->tz_cooling_active) { 1011149450Sume perf = sc->tz_zone.tc1 * (curr_temp - prev_temp) + 1012149450Sume sc->tz_zone.tc2 * (curr_temp - sc->tz_zone.psv); 1013148138Sume perf /= 10; 1014148138Sume 1015148138Sume if (perf != 0) { 1016148138Sume error = acpi_tz_cpufreq_update(sc, perf); 1017148138Sume 1018148138Sume /* 1019148138Sume * If error and not simply a higher priority setting was 1020148138Sume * active, disable cooling. 1021148138Sume */ 1022148138Sume if (error != 0 && error != EPERM) { 1023148138Sume device_printf(sc->tz_dev, 1024148138Sume "failed to set new freq, disabling passive cooling\n"); 1025148138Sume sc->tz_cooling_enabled = FALSE; 1026148138Sume } 1027148138Sume } 1028148138Sume } 1029149450Sume prev_temp = curr_temp; 1030148138Sume tsleep(&sc->tz_cooling_proc, PZERO, "cooling", 1031148138Sume hz * sc->tz_zone.tsp / 10); 1032148138Sume } 1033148138Sume if (sc->tz_cooling_active) { 1034148138Sume acpi_tz_cpufreq_restore(sc); 1035148138Sume sc->tz_cooling_active = FALSE; 1036148138Sume } 1037148703Sume sc->tz_cooling_proc = NULL; 1038148138Sume ACPI_LOCK(thermal); 1039148703Sume sc->tz_cooling_proc_running = FALSE; 1040148138Sume ACPI_UNLOCK(thermal); 1041148138Sume kthread_exit(0); 1042148138Sume} 1043148138Sume 1044148138Sume/* 1045148138Sume * TODO: We ignore _PSL (list of cooling devices) since cpufreq enumerates 1046148138Sume * all CPUs for us. However, it's possible in the future _PSL will 1047148138Sume * reference non-CPU devices so we may want to support it then. 1048148138Sume */ 1049148138Sumestatic int 1050148138Sumeacpi_tz_cooling_is_available(struct acpi_tz_softc *sc) 1051148138Sume{ 1052148138Sume return (sc->tz_zone.tc1 != -1 && sc->tz_zone.tc2 != -1 && 1053148138Sume sc->tz_zone.tsp != -1 && sc->tz_zone.tsp != 0 && 1054148138Sume sc->tz_zone.psv != -1); 1055148138Sume} 1056148138Sume 1057148138Sumestatic int 1058148138Sumeacpi_tz_cooling_thread_start(struct acpi_tz_softc *sc) 1059148138Sume{ 1060148138Sume int error; 1061148138Sume char name[16]; 1062148138Sume 1063148703Sume ACPI_LOCK(thermal); 1064148703Sume if (sc->tz_cooling_proc_running) { 1065148703Sume ACPI_UNLOCK(thermal); 1066148703Sume return (0); 1067148703Sume } 1068148703Sume sc->tz_cooling_proc_running = TRUE; 1069148703Sume ACPI_UNLOCK(thermal); 1070148138Sume error = 0; 1071148138Sume if (sc->tz_cooling_proc == NULL) { 1072148138Sume snprintf(name, sizeof(name), "acpi_cooling%d", 1073148138Sume device_get_unit(sc->tz_dev)); 1074148138Sume error = kthread_create(acpi_tz_cooling_thread, sc, 1075148138Sume &sc->tz_cooling_proc, RFHIGHPID, 0, name); 1076148703Sume if (error != 0) { 1077148138Sume device_printf(sc->tz_dev, "could not create thread - %d", error); 1078148703Sume ACPI_LOCK(thermal); 1079148703Sume sc->tz_cooling_proc_running = FALSE; 1080148703Sume ACPI_UNLOCK(thermal); 1081148703Sume } 1082148138Sume } 1083148138Sume return (error); 1084148138Sume} 1085