acpi_thermal.c revision 134909
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 134909 2004-09-07 17:02:08Z njl $"); 30119418Sobrien 3167761Smsmith#include "opt_acpi.h" 3267761Smsmith#include <sys/param.h> 3367761Smsmith#include <sys/kernel.h> 34133624Snjl#include <sys/bus.h> 3591126Smsmith#include <sys/kthread.h> 36133624Snjl#include <sys/malloc.h> 37129879Sphk#include <sys/module.h> 3867761Smsmith#include <sys/bus.h> 3991126Smsmith#include <sys/proc.h> 40128991Snjl#include <sys/reboot.h> 4179283Smsmith#include <sys/sysctl.h> 4291126Smsmith#include <sys/unistd.h> 4391640Siwasaki#include <sys/power.h> 4467761Smsmith 4567761Smsmith#include "acpi.h" 4667761Smsmith#include <dev/acpica/acpivar.h> 4767761Smsmith 48119529Snjl/* Hooks for the ACPI CA debugging infrastructure */ 4978999Smsmith#define _COMPONENT ACPI_THERMAL 5091126SmsmithACPI_MODULE_NAME("THERMAL") 5169744Smsmith 5271874Smsmith#define TZ_ZEROC 2732 5371874Smsmith#define TZ_KELVTOC(x) (((x) - TZ_ZEROC) / 10), (((x) - TZ_ZEROC) % 10) 5467761Smsmith 55125366Snjl#define TZ_NOTIFY_TEMPERATURE 0x80 /* Temperature changed. */ 56125366Snjl#define TZ_NOTIFY_LEVELS 0x81 /* Cooling levels changed. */ 57125366Snjl#define TZ_NOTIFY_DEVICES 0x82 /* Device lists changed. */ 58125366Snjl#define TZ_NOTIFY_CRITICAL 0xcc /* Fake notify that _CRT/_HOT reached. */ 5978915Smsmith 60125335Snjl/* Check for temperature changes every 10 seconds by default */ 61125335Snjl#define TZ_POLLRATE 10 6278915Smsmith 63125335Snjl/* Make sure the reported temperature is valid for this number of polls. */ 64125335Snjl#define TZ_VALIDCHECKS 3 65125335Snjl 66125366Snjl/* Notify the user we will be shutting down in one more poll cycle. */ 67125366Snjl#define TZ_NOTIFYCOUNT (TZ_VALIDCHECKS - 1) 68125366Snjl 69119529Snjl/* ACPI spec defines this */ 70119529Snjl#define TZ_NUMLEVELS 10 7179375Smsmithstruct acpi_tz_zone { 7278915Smsmith int ac[TZ_NUMLEVELS]; 7378915Smsmith ACPI_BUFFER al[TZ_NUMLEVELS]; 7478915Smsmith int crt; 7578915Smsmith int hot; 7678915Smsmith ACPI_BUFFER psl; 7778915Smsmith int psv; 7878915Smsmith int tc1; 7978915Smsmith int tc2; 8078915Smsmith int tsp; 8178915Smsmith int tzp; 8278915Smsmith}; 8378915Smsmith 8467761Smsmithstruct acpi_tz_softc { 85119529Snjl device_t tz_dev; 86119529Snjl ACPI_HANDLE tz_handle; /*Thermal zone handle*/ 87119529Snjl int tz_temperature; /*Current temperature*/ 88119529Snjl int tz_active; /*Current active cooling*/ 8979375Smsmith#define TZ_ACTIVE_NONE -1 90119529Snjl int tz_requested; /*Minimum active cooling*/ 91119529Snjl int tz_thflags; /*Current temp-related flags*/ 9279375Smsmith#define TZ_THFLAG_NONE 0 9379375Smsmith#define TZ_THFLAG_PSV (1<<0) 9479375Smsmith#define TZ_THFLAG_HOT (1<<2) 9579375Smsmith#define TZ_THFLAG_CRT (1<<3) 9679283Smsmith int tz_flags; 97119529Snjl#define TZ_FLAG_NO_SCP (1<<0) /*No _SCP method*/ 98119529Snjl#define TZ_FLAG_GETPROFILE (1<<1) /*Get power_profile in timeout*/ 99133624Snjl#define TZ_FLAG_GETSETTINGS (1<<2) /*Get devs/setpoints*/ 100119529Snjl struct timespec tz_cooling_started; 101119529Snjl /*Current cooling starting time*/ 10279283Smsmith 103119529Snjl struct sysctl_ctx_list tz_sysctl_ctx; 10479283Smsmith struct sysctl_oid *tz_sysctl_tree; 105133624Snjl eventhandler_tag tz_event; 106133624Snjl 107119529Snjl struct acpi_tz_zone tz_zone; /*Thermal zone parameters*/ 108125335Snjl int tz_validchecks; 10967761Smsmith}; 11067761Smsmith 11167761Smsmithstatic int acpi_tz_probe(device_t dev); 11267761Smsmithstatic int acpi_tz_attach(device_t dev); 11378915Smsmithstatic int acpi_tz_establish(struct acpi_tz_softc *sc); 114119529Snjlstatic void acpi_tz_monitor(void *Context); 115134909Snjl#if 0 11678915Smsmithstatic void acpi_tz_all_off(struct acpi_tz_softc *sc); 117134909Snjl#endif 11878915Smsmithstatic void acpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg); 11978915Smsmithstatic void acpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg); 120119529Snjlstatic void acpi_tz_getparam(struct acpi_tz_softc *sc, char *node, 121119529Snjl int *data); 12279283Smsmithstatic void acpi_tz_sanity(struct acpi_tz_softc *sc, int *val, char *what); 12379375Smsmithstatic int acpi_tz_active_sysctl(SYSCTL_HANDLER_ARGS); 124119529Snjlstatic void acpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, 125119529Snjl void *context); 126133624Snjlstatic void acpi_tz_signal(struct acpi_tz_softc *sc, int flags); 127133624Snjlstatic void acpi_tz_timeout(struct acpi_tz_softc *sc, int flags); 12891640Siwasakistatic void acpi_tz_power_profile(void *arg); 12991126Smsmithstatic void acpi_tz_thread(void *arg); 13091126Smsmith 13167761Smsmithstatic device_method_t acpi_tz_methods[] = { 13267761Smsmith /* Device interface */ 13367761Smsmith DEVMETHOD(device_probe, acpi_tz_probe), 13467761Smsmith DEVMETHOD(device_attach, acpi_tz_attach), 13567761Smsmith 13667761Smsmith {0, 0} 13767761Smsmith}; 13867761Smsmith 13967761Smsmithstatic driver_t acpi_tz_driver = { 14067761Smsmith "acpi_tz", 14167761Smsmith acpi_tz_methods, 14267761Smsmith sizeof(struct acpi_tz_softc), 14367761Smsmith}; 14467761Smsmith 14589054Smsmithstatic devclass_t acpi_tz_devclass; 14667761SmsmithDRIVER_MODULE(acpi_tz, acpi, acpi_tz_driver, acpi_tz_devclass, 0, 0); 147128071SnjlMODULE_DEPEND(acpi_tz, acpi, 1, 1, 1); 14867761Smsmith 14979283Smsmithstatic struct sysctl_ctx_list acpi_tz_sysctl_ctx; 15079283Smsmithstatic struct sysctl_oid *acpi_tz_sysctl_tree; 15179283Smsmith 152119529Snjl/* Minimum cooling run time */ 153119529Snjlstatic int acpi_tz_min_runtime = 0; 15488420Siwasakistatic int acpi_tz_polling_rate = TZ_POLLRATE; 15585699Siwasaki 156119529Snjl/* Timezone polling thread */ 157119529Snjlstatic struct proc *acpi_tz_proc; 158133624SnjlACPI_LOCK_DECL(thermal, "ACPI thermal zone"); 159119529Snjl 16067761Smsmithstatic int 16167761Smsmithacpi_tz_probe(device_t dev) 16267761Smsmith{ 16378999Smsmith int result; 16478999Smsmith 165119529Snjl if (acpi_get_type(dev) == ACPI_TYPE_THERMAL && !acpi_disabled("thermal")) { 166120453Snjl device_set_desc(dev, "Thermal Zone"); 16778999Smsmith result = -10; 168133624Snjl } else 16978999Smsmith result = ENXIO; 170119529Snjl return (result); 17167761Smsmith} 17267761Smsmith 17367761Smsmithstatic int 17467761Smsmithacpi_tz_attach(device_t dev) 17567761Smsmith{ 17667761Smsmith struct acpi_tz_softc *sc; 17779283Smsmith struct acpi_softc *acpi_sc; 17878915Smsmith int error; 17979283Smsmith char oidname[8]; 18067761Smsmith 18196926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 18269744Smsmith 18367761Smsmith sc = device_get_softc(dev); 18467761Smsmith sc->tz_dev = dev; 18567761Smsmith sc->tz_handle = acpi_get_handle(dev); 18679375Smsmith sc->tz_requested = TZ_ACTIVE_NONE; 18767761Smsmith 18878915Smsmith /* 18978915Smsmith * Parse the current state of the thermal zone and build control 190133624Snjl * structures. We don't need to worry about interference with the 191133624Snjl * control thread since we haven't fully attached this device yet. 19278915Smsmith */ 19378915Smsmith if ((error = acpi_tz_establish(sc)) != 0) 194133624Snjl return (error); 195133624Snjl 19678915Smsmith /* 19778915Smsmith * Register for any Notify events sent to this zone. 19878915Smsmith */ 19971874Smsmith AcpiInstallNotifyHandler(sc->tz_handle, ACPI_DEVICE_NOTIFY, 20078999Smsmith acpi_tz_notify_handler, sc); 20170271Stakawata 20271874Smsmith /* 20379283Smsmith * Create our sysctl nodes. 20479283Smsmith * 20579283Smsmith * XXX we need a mechanism for adding nodes under ACPI. 20679283Smsmith */ 20779283Smsmith if (device_get_unit(dev) == 0) { 20879283Smsmith acpi_sc = acpi_device_get_parent_softc(dev); 20979283Smsmith sysctl_ctx_init(&acpi_tz_sysctl_ctx); 21079283Smsmith acpi_tz_sysctl_tree = SYSCTL_ADD_NODE(&acpi_tz_sysctl_ctx, 211119529Snjl SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), 212119529Snjl OID_AUTO, "thermal", CTLFLAG_RD, 0, ""); 21385699Siwasaki SYSCTL_ADD_INT(&acpi_tz_sysctl_ctx, 21485699Siwasaki SYSCTL_CHILDREN(acpi_tz_sysctl_tree), 21585699Siwasaki OID_AUTO, "min_runtime", CTLFLAG_RD | CTLFLAG_RW, 216119529Snjl &acpi_tz_min_runtime, 0, 217119529Snjl "minimum cooling run time in sec"); 21888420Siwasaki SYSCTL_ADD_INT(&acpi_tz_sysctl_ctx, 21988420Siwasaki SYSCTL_CHILDREN(acpi_tz_sysctl_tree), 22088420Siwasaki OID_AUTO, "polling_rate", CTLFLAG_RD | CTLFLAG_RW, 22188420Siwasaki &acpi_tz_polling_rate, 0, "monitor polling rate"); 22279283Smsmith } 22379283Smsmith sysctl_ctx_init(&sc->tz_sysctl_ctx); 22479283Smsmith sprintf(oidname, "tz%d", device_get_unit(dev)); 22579283Smsmith sc->tz_sysctl_tree = SYSCTL_ADD_NODE(&sc->tz_sysctl_ctx, 226119529Snjl SYSCTL_CHILDREN(acpi_tz_sysctl_tree), 227119529Snjl OID_AUTO, oidname, CTLFLAG_RD, 0, ""); 228134541Speter SYSCTL_ADD_OPAQUE(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 229134541Speter OID_AUTO, "temperature", CTLFLAG_RD, &sc->tz_temperature, 230134541Speter sizeof(sc->tz_temperature), "IK", "current thermal zone temperature"); 23179375Smsmith SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 23279375Smsmith OID_AUTO, "active", CTLTYPE_INT | CTLFLAG_RW, 23379375Smsmith sc, 0, acpi_tz_active_sysctl, "I", ""); 23479375Smsmith 23579283Smsmith SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 23679375Smsmith OID_AUTO, "thermal_flags", CTLFLAG_RD, 23779375Smsmith &sc->tz_thflags, 0, "thermal zone flags"); 23879283Smsmith SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 23979283Smsmith OID_AUTO, "_PSV", CTLFLAG_RD, 24079375Smsmith &sc->tz_zone.psv, 0, ""); 24186399Siwasaki SYSCTL_ADD_OPAQUE(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 242134541Speter OID_AUTO, "_HOT", CTLFLAG_RD, &sc->tz_zone.hot, 243134541Speter sizeof(sc->tz_zone.hot), "IK", ""); 244134541Speter SYSCTL_ADD_OPAQUE(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 245134541Speter OID_AUTO, "_CRT", CTLFLAG_RD, &sc->tz_zone.crt, 246134541Speter sizeof(sc->tz_zone.crt), "IK", ""); 247134541Speter SYSCTL_ADD_OPAQUE(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 24886399Siwasaki OID_AUTO, "_ACx", CTLFLAG_RD, &sc->tz_zone.ac, 249134541Speter sizeof(sc->tz_zone.ac), "IK", ""); 25079283Smsmith 25179283Smsmith /* 252133624Snjl * Create our thread; we only need one, it will service all of the 253133624Snjl * thermal zones. Register our power profile event handler. 25479375Smsmith */ 255133624Snjl sc->tz_event = EVENTHANDLER_REGISTER(power_profile_change, 256133624Snjl acpi_tz_power_profile, sc, 0); 257133624Snjl if (acpi_tz_proc == NULL) { 258133624Snjl error = kthread_create(acpi_tz_thread, NULL, &acpi_tz_proc, 259133624Snjl RFHIGHPID, 0, "acpi_thermal"); 260133624Snjl if (error != 0) { 261133624Snjl device_printf(sc->tz_dev, "could not create thread - %d", error); 262133624Snjl goto out; 263133624Snjl } 264133624Snjl } 26579375Smsmith 26679375Smsmith /* 267133624Snjl * Flag the event handler for a manual invocation by our timeout. 268133624Snjl * We defer it like this so that the rest of the subsystem has time 269133624Snjl * to come up. Don't bother evaluating/printing the temperature at 270133624Snjl * this point; on many systems it'll be bogus until the EC is running. 27171874Smsmith */ 272133624Snjl sc->tz_flags |= TZ_FLAG_GETPROFILE; 27378999Smsmith 274133624Snjlout: 275133624Snjl if (error != 0) { 276133624Snjl EVENTHANDLER_DEREGISTER(power_profile_change, sc->tz_event); 277133624Snjl AcpiRemoveNotifyHandler(sc->tz_handle, ACPI_DEVICE_NOTIFY, 278133624Snjl acpi_tz_notify_handler); 279133624Snjl sysctl_ctx_free(&sc->tz_sysctl_ctx); 28091126Smsmith } 281119529Snjl return_VALUE (error); 28267761Smsmith} 28370271Stakawata 28478915Smsmith/* 28578915Smsmith * Parse the current state of this thermal zone and set up to use it. 28678915Smsmith * 28778915Smsmith * Note that we may have previous state, which will have to be discarded. 28878915Smsmith */ 28978915Smsmithstatic int 29078915Smsmithacpi_tz_establish(struct acpi_tz_softc *sc) 29178915Smsmith{ 29278915Smsmith ACPI_OBJECT *obj; 29378915Smsmith int i; 29478915Smsmith char nbuf[8]; 29578915Smsmith 29696926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 29778915Smsmith 298134909Snjl /* Erase any existing state. */ 29978915Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) 30079375Smsmith if (sc->tz_zone.al[i].Pointer != NULL) 30179375Smsmith AcpiOsFree(sc->tz_zone.al[i].Pointer); 30279375Smsmith if (sc->tz_zone.psl.Pointer != NULL) 30379375Smsmith AcpiOsFree(sc->tz_zone.psl.Pointer); 30479375Smsmith bzero(&sc->tz_zone, sizeof(sc->tz_zone)); 30578915Smsmith 306119529Snjl /* Evaluate thermal zone parameters. */ 30778915Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) { 30878915Smsmith sprintf(nbuf, "_AC%d", i); 30979375Smsmith acpi_tz_getparam(sc, nbuf, &sc->tz_zone.ac[i]); 31078915Smsmith sprintf(nbuf, "_AL%d", i); 31191126Smsmith sc->tz_zone.al[i].Length = ACPI_ALLOCATE_BUFFER; 31291126Smsmith sc->tz_zone.al[i].Pointer = NULL; 31391126Smsmith AcpiEvaluateObject(sc->tz_handle, nbuf, NULL, &sc->tz_zone.al[i]); 31479375Smsmith obj = (ACPI_OBJECT *)sc->tz_zone.al[i].Pointer; 31578915Smsmith if (obj != NULL) { 316119529Snjl /* Should be a package containing a list of power objects */ 31778915Smsmith if (obj->Type != ACPI_TYPE_PACKAGE) { 318119529Snjl device_printf(sc->tz_dev, "%s has unknown type %d, rejecting\n", 31978915Smsmith nbuf, obj->Type); 320119529Snjl return_VALUE (ENXIO); 32178915Smsmith } 32278915Smsmith } 32378915Smsmith } 32479375Smsmith acpi_tz_getparam(sc, "_CRT", &sc->tz_zone.crt); 32579375Smsmith acpi_tz_getparam(sc, "_HOT", &sc->tz_zone.hot); 32691126Smsmith sc->tz_zone.psl.Length = ACPI_ALLOCATE_BUFFER; 32791126Smsmith sc->tz_zone.psl.Pointer = NULL; 32891126Smsmith AcpiEvaluateObject(sc->tz_handle, "_PSL", NULL, &sc->tz_zone.psl); 32979375Smsmith acpi_tz_getparam(sc, "_PSV", &sc->tz_zone.psv); 33079375Smsmith acpi_tz_getparam(sc, "_TC1", &sc->tz_zone.tc1); 33179375Smsmith acpi_tz_getparam(sc, "_TC2", &sc->tz_zone.tc2); 33279375Smsmith acpi_tz_getparam(sc, "_TSP", &sc->tz_zone.tsp); 33379375Smsmith acpi_tz_getparam(sc, "_TZP", &sc->tz_zone.tzp); 33478915Smsmith 33578915Smsmith /* 33679283Smsmith * Sanity-check the values we've been given. 33779283Smsmith * 33879283Smsmith * XXX what do we do about systems that give us the same value for 33979283Smsmith * more than one of these setpoints? 34079283Smsmith */ 34179375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.crt, "_CRT"); 34279375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.hot, "_HOT"); 34379375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.psv, "_PSV"); 34479283Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) 34579375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.ac[i], "_ACx"); 34679283Smsmith 347119529Snjl return_VALUE (0); 34878915Smsmith} 34978915Smsmith 350133624Snjlstatic char *aclevel_string[] = { 351133624Snjl "NONE", "_AC0", "_AC1", "_AC2", "_AC3", "_AC4", 352133624Snjl "_AC5", "_AC6", "_AC7", "_AC8", "_AC9" 353133624Snjl}; 35485699Siwasaki 35585699Siwasakistatic __inline const char * 35685699Siwasakiacpi_tz_aclevel_string(int active) 35785699Siwasaki{ 358133624Snjl if (active < -1 || active >= TZ_NUMLEVELS) 359133624Snjl return (aclevel_string[0]); 36085699Siwasaki 361133624Snjl return (aclevel_string[active + 1]); 36285699Siwasaki} 36385699Siwasaki 36478915Smsmith/* 36578915Smsmith * Evaluate the condition of a thermal zone, take appropriate actions. 36678915Smsmith */ 36771874Smsmithstatic void 368119529Snjlacpi_tz_monitor(void *Context) 36971874Smsmith{ 370119529Snjl struct acpi_tz_softc *sc; 371119529Snjl struct timespec curtime; 37279283Smsmith int temp; 37378915Smsmith int i; 37479283Smsmith int newactive, newflags; 37586399Siwasaki ACPI_STATUS status; 37670271Stakawata 37796926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 37870271Stakawata 379119529Snjl sc = (struct acpi_tz_softc *)Context; 38088420Siwasaki 381119529Snjl /* Get the current temperature. */ 382126560Snjl status = acpi_GetInteger(sc->tz_handle, "_TMP", &temp); 383119529Snjl if (ACPI_FAILURE(status)) { 38486552Siwasaki ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 38586552Siwasaki "error fetching current temperature -- %s\n", 38686552Siwasaki AcpiFormatException(status)); 38778915Smsmith /* XXX disable zone? go to max cooling? */ 388133624Snjl return_VOID; 38971874Smsmith } 39088420Siwasaki 39182372Smsmith ACPI_DEBUG_PRINT((ACPI_DB_VALUES, "got %d.%dC\n", TZ_KELVTOC(temp))); 39279283Smsmith sc->tz_temperature = temp; 39378915Smsmith 39478915Smsmith /* 39578915Smsmith * Work out what we ought to be doing right now. 39679283Smsmith * 39779283Smsmith * Note that the _ACx levels sort from hot to cold. 39878915Smsmith */ 39979283Smsmith newactive = TZ_ACTIVE_NONE; 40079375Smsmith for (i = TZ_NUMLEVELS - 1; i >= 0; i--) { 40179375Smsmith if ((sc->tz_zone.ac[i] != -1) && (temp >= sc->tz_zone.ac[i])) { 40279283Smsmith newactive = i; 40382967Siwasaki if (sc->tz_active != newactive) { 404119529Snjl ACPI_VPRINT(sc->tz_dev, 405119529Snjl acpi_device_get_parent_softc(sc->tz_dev), 406119529Snjl "_AC%d: temperature %d.%d >= setpoint %d.%d\n", i, 407119529Snjl TZ_KELVTOC(temp), TZ_KELVTOC(sc->tz_zone.ac[i])); 40885699Siwasaki getnanotime(&sc->tz_cooling_started); 40982967Siwasaki } 41079375Smsmith } 41179375Smsmith } 41279283Smsmith 41385699Siwasaki /* 41485699Siwasaki * We are going to get _ACx level down (colder side), but give a guaranteed 41585699Siwasaki * minimum cooling run time if requested. 41685699Siwasaki */ 41785699Siwasaki if (acpi_tz_min_runtime > 0 && sc->tz_active != TZ_ACTIVE_NONE && 41885699Siwasaki (newactive == TZ_ACTIVE_NONE || newactive > sc->tz_active)) { 419119529Snjl 42085699Siwasaki getnanotime(&curtime); 42185699Siwasaki timespecsub(&curtime, &sc->tz_cooling_started); 422119529Snjl if (curtime.tv_sec < acpi_tz_min_runtime) 42385699Siwasaki newactive = sc->tz_active; 42485699Siwasaki } 42585699Siwasaki 426119529Snjl /* Handle user override of active mode */ 427126662Snjl if (sc->tz_requested != TZ_ACTIVE_NONE && sc->tz_requested < newactive) 42879375Smsmith newactive = sc->tz_requested; 42978915Smsmith 43079375Smsmith /* update temperature-related flags */ 43179375Smsmith newflags = TZ_THFLAG_NONE; 432124439Snjl if (sc->tz_zone.psv != -1 && temp >= sc->tz_zone.psv) 43379375Smsmith newflags |= TZ_THFLAG_PSV; 434124439Snjl if (sc->tz_zone.hot != -1 && temp >= sc->tz_zone.hot) 43579375Smsmith newflags |= TZ_THFLAG_HOT; 436124439Snjl if (sc->tz_zone.crt != -1 && temp >= sc->tz_zone.crt) 43779375Smsmith newflags |= TZ_THFLAG_CRT; 43879375Smsmith 439119529Snjl /* If the active cooling state has changed, we have to switch things. */ 44079283Smsmith if (newactive != sc->tz_active) { 441119529Snjl /* Turn off the cooling devices that are on, if any are */ 44279283Smsmith if (sc->tz_active != TZ_ACTIVE_NONE) 443119529Snjl acpi_ForeachPackageObject( 444119529Snjl (ACPI_OBJECT *)sc->tz_zone.al[sc->tz_active].Pointer, 445119529Snjl acpi_tz_switch_cooler_off, sc); 44678915Smsmith 447119529Snjl /* Turn on cooling devices that are required, if any are */ 448119529Snjl if (newactive != TZ_ACTIVE_NONE) { 449119529Snjl acpi_ForeachPackageObject( 450119529Snjl (ACPI_OBJECT *)sc->tz_zone.al[newactive].Pointer, 451119529Snjl acpi_tz_switch_cooler_on, sc); 452119529Snjl } 45386552Siwasaki ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 454119529Snjl "switched from %s to %s: %d.%dC\n", 455119529Snjl acpi_tz_aclevel_string(sc->tz_active), 456119529Snjl acpi_tz_aclevel_string(newactive), TZ_KELVTOC(temp)); 45779283Smsmith sc->tz_active = newactive; 45879283Smsmith } 45978915Smsmith 460119529Snjl /* XXX (de)activate any passive cooling that may be required. */ 46178915Smsmith 46278915Smsmith /* 463125335Snjl * If the temperature is at _HOT or _CRT, increment our event count. 464125335Snjl * If it has occurred enough times, shutdown the system. This is 465125335Snjl * needed because some systems will report an invalid high temperature 466125335Snjl * for one poll cycle. It is suspected this is due to the embedded 467125335Snjl * controller timing out. A typical value is 138C for one cycle on 468125335Snjl * a system that is otherwise 65C. 469125366Snjl * 470125366Snjl * If we're almost at that threshold, notify the user through devd(8). 47178915Smsmith */ 472125335Snjl if ((newflags & (TZ_THFLAG_HOT | TZ_THFLAG_CRT)) != 0) { 473125366Snjl sc->tz_validchecks++; 474125366Snjl if (sc->tz_validchecks == TZ_VALIDCHECKS) { 475125335Snjl device_printf(sc->tz_dev, 476125335Snjl "WARNING - current temperature (%d.%dC) exceeds safe limits\n", 477125335Snjl TZ_KELVTOC(sc->tz_temperature)); 478125335Snjl shutdown_nice(RB_POWEROFF); 479125366Snjl } else if (sc->tz_validchecks == TZ_NOTIFYCOUNT) 480125366Snjl acpi_UserNotify("Thermal", sc->tz_handle, TZ_NOTIFY_CRITICAL); 481125335Snjl } else { 482125335Snjl sc->tz_validchecks = 0; 48378915Smsmith } 48479375Smsmith sc->tz_thflags = newflags; 48578915Smsmith 48671874Smsmith return_VOID; 48771874Smsmith} 48870271Stakawata 489134909Snjl#if 0 49078915Smsmith/* 49178915Smsmith * Turn off all the cooling devices. 49278915Smsmith */ 49371874Smsmithstatic void 49478915Smsmithacpi_tz_all_off(struct acpi_tz_softc *sc) 49578915Smsmith{ 49678915Smsmith int i; 49778915Smsmith 49896926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 49978999Smsmith 500119529Snjl /* Scan all the _ALx objects and turn them all off. */ 50178915Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) { 50279375Smsmith if (sc->tz_zone.al[i].Pointer == NULL) 50378915Smsmith continue; 50479375Smsmith acpi_ForeachPackageObject((ACPI_OBJECT *)sc->tz_zone.al[i].Pointer, 50578915Smsmith acpi_tz_switch_cooler_off, sc); 50678915Smsmith } 50778915Smsmith 50878915Smsmith /* 50978915Smsmith * XXX revert any passive-cooling options. 51078915Smsmith */ 51178915Smsmith 51279283Smsmith sc->tz_active = TZ_ACTIVE_NONE; 51379375Smsmith sc->tz_thflags = TZ_THFLAG_NONE; 514119529Snjl 51578915Smsmith return_VOID; 51678915Smsmith} 517134909Snjl#endif 51878915Smsmith 51978915Smsmith/* 52078915Smsmith * Given an object, verify that it's a reference to a device of some sort, 52178915Smsmith * and try to switch it off. 52278915Smsmith */ 52378915Smsmithstatic void 52478915Smsmithacpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg) 52578915Smsmith{ 526128047Snjl ACPI_HANDLE cooler; 52778915Smsmith 52896926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 52978915Smsmith 530128047Snjl cooler = acpi_GetReference(NULL, obj); 531128047Snjl if (cooler == NULL) { 532128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get handle\n")); 533128047Snjl return_VOID; 534128047Snjl } 535102470Siwasaki 536128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s off\n", 537128047Snjl acpi_name(cooler))); 538128150Snjl acpi_pwr_switch_consumer(cooler, ACPI_STATE_D3); 539119529Snjl 54079375Smsmith return_VOID; 54178915Smsmith} 54278915Smsmith 54378915Smsmith/* 54478915Smsmith * Given an object, verify that it's a reference to a device of some sort, 54578915Smsmith * and try to switch it on. 54678915Smsmith * 547128047Snjl * XXX replication of off/on function code is bad. 54878915Smsmith */ 54978915Smsmithstatic void 55078915Smsmithacpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg) 55178915Smsmith{ 55278915Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg; 55378999Smsmith ACPI_HANDLE cooler; 55479375Smsmith ACPI_STATUS status; 55579375Smsmith 55696926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 55778915Smsmith 558128047Snjl cooler = acpi_GetReference(NULL, obj); 559128047Snjl if (cooler == NULL) { 560128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get handle\n")); 561128047Snjl return_VOID; 562128047Snjl } 563102470Siwasaki 564128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s on\n", 565128047Snjl acpi_name(cooler))); 566128047Snjl status = acpi_pwr_switch_consumer(cooler, ACPI_STATE_D0); 567128047Snjl if (ACPI_FAILURE(status)) { 568128047Snjl ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 569128047Snjl "failed to activate %s - %s\n", acpi_name(cooler), 570128047Snjl AcpiFormatException(status)); 57178915Smsmith } 572119529Snjl 573119529Snjl return_VOID; 57478915Smsmith} 57578915Smsmith 57678915Smsmith/* 57778915Smsmith * Read/debug-print a parameter, default it to -1. 57878915Smsmith */ 57978915Smsmithstatic void 58078915Smsmithacpi_tz_getparam(struct acpi_tz_softc *sc, char *node, int *data) 58178915Smsmith{ 58278915Smsmith 58396926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 58478915Smsmith 585126560Snjl if (ACPI_FAILURE(acpi_GetInteger(sc->tz_handle, node, data))) { 58678915Smsmith *data = -1; 58778915Smsmith } else { 588119529Snjl ACPI_DEBUG_PRINT((ACPI_DB_VALUES, "%s.%s = %d\n", 589119529Snjl acpi_name(sc->tz_handle), node, *data)); 59078915Smsmith } 591119529Snjl 59278915Smsmith return_VOID; 59378915Smsmith} 59479283Smsmith 59579283Smsmith/* 59679283Smsmith * Sanity-check a temperature value. Assume that setpoints 59779283Smsmith * should be between 0C and 150C. 59879283Smsmith */ 59979283Smsmithstatic void 60079283Smsmithacpi_tz_sanity(struct acpi_tz_softc *sc, int *val, char *what) 60179283Smsmith{ 602119529Snjl if (*val != -1 && (*val < TZ_ZEROC || *val > TZ_ZEROC + 1500)) { 60379283Smsmith device_printf(sc->tz_dev, "%s value is absurd, ignored (%d.%dC)\n", 60479283Smsmith what, TZ_KELVTOC(*val)); 60579283Smsmith *val = -1; 60679283Smsmith } 60779283Smsmith} 60879375Smsmith 60979375Smsmith/* 61079375Smsmith * Respond to a sysctl on the active state node. 61179375Smsmith */ 61279375Smsmithstatic int 61379375Smsmithacpi_tz_active_sysctl(SYSCTL_HANDLER_ARGS) 61479375Smsmith{ 61579375Smsmith struct acpi_tz_softc *sc; 61679375Smsmith int active; 61779375Smsmith int error; 61879375Smsmith 61979375Smsmith sc = (struct acpi_tz_softc *)oidp->oid_arg1; 62079375Smsmith active = sc->tz_active; 62179375Smsmith error = sysctl_handle_int(oidp, &active, 0, req); 62279375Smsmith 623119529Snjl /* Error or no new value */ 624119529Snjl if (error != 0 || req->newptr == NULL) 625133624Snjl return (error); 626133624Snjl if (active < -1 || active >= TZ_NUMLEVELS) 627133624Snjl return (EINVAL); 62879375Smsmith 629119529Snjl /* Set new preferred level and re-switch */ 63079375Smsmith sc->tz_requested = active; 631133624Snjl acpi_tz_signal(sc, 0); 632133624Snjl return (0); 63379375Smsmith} 63479375Smsmith 63578915Smsmithstatic void 63671874Smsmithacpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context) 63771874Smsmith{ 63878915Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)context; 63978915Smsmith 64096926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 64170271Stakawata 642133624Snjl switch (notify) { 64378915Smsmith case TZ_NOTIFY_TEMPERATURE: 644119529Snjl /* Temperature change occurred */ 645133624Snjl acpi_tz_signal(sc, 0); 64678915Smsmith break; 64778915Smsmith case TZ_NOTIFY_DEVICES: 64878915Smsmith case TZ_NOTIFY_LEVELS: 649119529Snjl /* Zone devices/setpoints changed */ 650133624Snjl acpi_tz_signal(sc, TZ_FLAG_GETSETTINGS); 65178915Smsmith break; 65278915Smsmith default: 65386552Siwasaki ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 654119529Snjl "unknown Notify event 0x%x\n", notify); 65578915Smsmith break; 65671874Smsmith } 657119529Snjl 658121493Snjl acpi_UserNotify("Thermal", h, notify); 659121493Snjl 66071874Smsmith return_VOID; 66171874Smsmith} 66270271Stakawata 663133624Snjlstatic void 664133624Snjlacpi_tz_signal(struct acpi_tz_softc *sc, int flags) 665133624Snjl{ 666133624Snjl ACPI_LOCK(thermal); 667133624Snjl sc->tz_flags |= flags; 668133624Snjl ACPI_UNLOCK(thermal); 669133624Snjl wakeup(&acpi_tz_proc); 670133624Snjl} 671133624Snjl 67278915Smsmith/* 673134909Snjl * Notifies can be generated asynchronously but have also been seen to be 674134909Snjl * triggered by other thermal methods. One system generates a notify of 675134909Snjl * 0x81 when the fan is turned on or off. Another generates it when _SCP 676134909Snjl * is called. To handle these situations, we check the zone via 677134909Snjl * acpi_tz_monitor() before evaluating changes to setpoints or the cooling 678134909Snjl * policy. 67978915Smsmith */ 68078915Smsmithstatic void 681133624Snjlacpi_tz_timeout(struct acpi_tz_softc *sc, int flags) 68278915Smsmith{ 683134909Snjl 684134909Snjl /* Check the current temperature and take action based on it */ 685134909Snjl acpi_tz_monitor(sc); 686134909Snjl 687133624Snjl /* If requested, get the power profile settings. */ 688133624Snjl if (flags & TZ_FLAG_GETPROFILE) 689133624Snjl acpi_tz_power_profile(sc); 69079375Smsmith 691134909Snjl /* 692134909Snjl * If requested, check for new devices/setpoints. After finding them, 693134909Snjl * check if we need to switch fans based on the new values. 694134909Snjl */ 695134909Snjl if (flags & TZ_FLAG_GETSETTINGS) { 696133624Snjl acpi_tz_establish(sc); 697134909Snjl acpi_tz_monitor(sc); 698134909Snjl } 69978915Smsmith 70078915Smsmith /* XXX passive cooling actions? */ 70178915Smsmith} 70279375Smsmith 70379375Smsmith/* 70479375Smsmith * System power profile may have changed; fetch and notify the 70579375Smsmith * thermal zone accordingly. 70679375Smsmith * 70779375Smsmith * Since this can be called from an arbitrary eventhandler, it needs 70879375Smsmith * to get the ACPI lock itself. 70979375Smsmith */ 71079375Smsmithstatic void 71191640Siwasakiacpi_tz_power_profile(void *arg) 71279375Smsmith{ 71379375Smsmith ACPI_STATUS status; 71479375Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg; 71591640Siwasaki int state; 71679375Smsmith 71791640Siwasaki state = power_profile_get_state(); 718119529Snjl if (state != POWER_PROFILE_PERFORMANCE && state != POWER_PROFILE_ECONOMY) 719119529Snjl return; 72091640Siwasaki 72179375Smsmith /* check that we haven't decided there's no _SCP method */ 722119529Snjl if ((sc->tz_flags & TZ_FLAG_NO_SCP) == 0) { 72379375Smsmith 724119529Snjl /* Call _SCP to set the new profile */ 725126560Snjl status = acpi_SetInteger(sc->tz_handle, "_SCP", 726126560Snjl (state == POWER_PROFILE_PERFORMANCE) ? 0 : 1); 727119529Snjl if (ACPI_FAILURE(status)) { 72879385Smsmith if (status != AE_NOT_FOUND) 729119529Snjl ACPI_VPRINT(sc->tz_dev, 730119529Snjl acpi_device_get_parent_softc(sc->tz_dev), 731119529Snjl "can't evaluate %s._SCP - %s\n", 732119529Snjl acpi_name(sc->tz_handle), 733119529Snjl AcpiFormatException(status)); 73479375Smsmith sc->tz_flags |= TZ_FLAG_NO_SCP; 73579375Smsmith } else { 736119529Snjl /* We have to re-evaluate the entire zone now */ 737133624Snjl acpi_tz_signal(sc, TZ_FLAG_GETSETTINGS); 73879375Smsmith } 73979375Smsmith } 74079375Smsmith} 74179375Smsmith 74291126Smsmith/* 74391126Smsmith * Thermal zone monitor thread. 74491126Smsmith */ 74591126Smsmithstatic void 74691126Smsmithacpi_tz_thread(void *arg) 74791126Smsmith{ 74891126Smsmith device_t *devs; 74991126Smsmith int devcount, i; 750133624Snjl int flags; 751133624Snjl struct acpi_tz_softc **sc; 75291126Smsmith 75396926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 75491126Smsmith 75591126Smsmith devs = NULL; 75691126Smsmith devcount = 0; 757133624Snjl sc = NULL; 75891126Smsmith 75991126Smsmith for (;;) { 760133624Snjl /* If the number of devices has changed, re-evaluate. */ 761133624Snjl if (devclass_get_maxunit(acpi_tz_devclass) != devcount) { 762133624Snjl if (devs != NULL) { 763133624Snjl free(devs, M_TEMP); 764133624Snjl free(sc, M_TEMP); 765133624Snjl } 766133624Snjl devclass_get_devices(acpi_tz_devclass, &devs, &devcount); 767133624Snjl sc = malloc(sizeof(struct acpi_tz_softc *) * devcount, M_TEMP, 768133624Snjl M_WAITOK | M_ZERO); 769133624Snjl for (i = 0; i < devcount; i++) 770133624Snjl sc[i] = device_get_softc(devs[i]); 771133624Snjl } 77291126Smsmith 773133624Snjl /* Check for temperature events and act on them. */ 774133624Snjl for (i = 0; i < devcount; i++) { 775133624Snjl ACPI_LOCK(thermal); 776133624Snjl flags = sc[i]->tz_flags; 777133624Snjl sc[i]->tz_flags &= TZ_FLAG_NO_SCP; 778133624Snjl ACPI_UNLOCK(thermal); 779133624Snjl acpi_tz_timeout(sc[i], flags); 780133624Snjl } 78191215Smsmith 782133624Snjl /* If more work to do, don't go to sleep yet. */ 783133624Snjl ACPI_LOCK(thermal); 784133624Snjl for (i = 0; i < devcount; i++) { 785133624Snjl if (sc[i]->tz_flags & ~TZ_FLAG_NO_SCP) 786133624Snjl break; 787133624Snjl } 78891126Smsmith 789133624Snjl /* 790133624Snjl * If we have no more work, sleep for a while, setting PDROP so that 791133624Snjl * the mutex will not be reacquired. Otherwise, drop the mutex and 792133624Snjl * loop to handle more events. 793133624Snjl */ 794133624Snjl if (i == devcount) 795133624Snjl msleep(&acpi_tz_proc, &thermal_mutex, PZERO | PDROP, "tzpoll", 796133624Snjl hz * acpi_tz_polling_rate); 797133624Snjl else 798133624Snjl ACPI_UNLOCK(thermal); 79991126Smsmith } 80091126Smsmith} 801