acpi_thermal.c revision 135548
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 135548 2004-09-21 18:39:10Z 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); 11578915Smsmithstatic void acpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg); 11678915Smsmithstatic void acpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg); 117119529Snjlstatic void acpi_tz_getparam(struct acpi_tz_softc *sc, char *node, 118119529Snjl int *data); 11979283Smsmithstatic void acpi_tz_sanity(struct acpi_tz_softc *sc, int *val, char *what); 12079375Smsmithstatic int acpi_tz_active_sysctl(SYSCTL_HANDLER_ARGS); 121119529Snjlstatic void acpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, 122119529Snjl void *context); 123133624Snjlstatic void acpi_tz_signal(struct acpi_tz_softc *sc, int flags); 124133624Snjlstatic void acpi_tz_timeout(struct acpi_tz_softc *sc, int flags); 12591640Siwasakistatic void acpi_tz_power_profile(void *arg); 12691126Smsmithstatic void acpi_tz_thread(void *arg); 12791126Smsmith 12867761Smsmithstatic device_method_t acpi_tz_methods[] = { 12967761Smsmith /* Device interface */ 13067761Smsmith DEVMETHOD(device_probe, acpi_tz_probe), 13167761Smsmith DEVMETHOD(device_attach, acpi_tz_attach), 13267761Smsmith 13367761Smsmith {0, 0} 13467761Smsmith}; 13567761Smsmith 13667761Smsmithstatic driver_t acpi_tz_driver = { 13767761Smsmith "acpi_tz", 13867761Smsmith acpi_tz_methods, 13967761Smsmith sizeof(struct acpi_tz_softc), 14067761Smsmith}; 14167761Smsmith 14289054Smsmithstatic devclass_t acpi_tz_devclass; 14367761SmsmithDRIVER_MODULE(acpi_tz, acpi, acpi_tz_driver, acpi_tz_devclass, 0, 0); 144128071SnjlMODULE_DEPEND(acpi_tz, acpi, 1, 1, 1); 14567761Smsmith 14679283Smsmithstatic struct sysctl_ctx_list acpi_tz_sysctl_ctx; 14779283Smsmithstatic struct sysctl_oid *acpi_tz_sysctl_tree; 14879283Smsmith 149119529Snjl/* Minimum cooling run time */ 150119529Snjlstatic int acpi_tz_min_runtime = 0; 15188420Siwasakistatic int acpi_tz_polling_rate = TZ_POLLRATE; 15285699Siwasaki 153119529Snjl/* Timezone polling thread */ 154119529Snjlstatic struct proc *acpi_tz_proc; 155133624SnjlACPI_LOCK_DECL(thermal, "ACPI thermal zone"); 156119529Snjl 15767761Smsmithstatic int 15867761Smsmithacpi_tz_probe(device_t dev) 15967761Smsmith{ 16078999Smsmith int result; 16178999Smsmith 162119529Snjl if (acpi_get_type(dev) == ACPI_TYPE_THERMAL && !acpi_disabled("thermal")) { 163120453Snjl device_set_desc(dev, "Thermal Zone"); 16478999Smsmith result = -10; 165133624Snjl } else 16678999Smsmith result = ENXIO; 167119529Snjl return (result); 16867761Smsmith} 16967761Smsmith 17067761Smsmithstatic int 17167761Smsmithacpi_tz_attach(device_t dev) 17267761Smsmith{ 17367761Smsmith struct acpi_tz_softc *sc; 17479283Smsmith struct acpi_softc *acpi_sc; 17578915Smsmith int error; 17679283Smsmith char oidname[8]; 17767761Smsmith 17896926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 17969744Smsmith 18067761Smsmith sc = device_get_softc(dev); 18167761Smsmith sc->tz_dev = dev; 18267761Smsmith sc->tz_handle = acpi_get_handle(dev); 18379375Smsmith sc->tz_requested = TZ_ACTIVE_NONE; 184135548Snjl sc->tz_active = TZ_ACTIVE_NONE; 185135548Snjl sc->tz_thflags = TZ_THFLAG_NONE; 18667761Smsmith 18778915Smsmith /* 18878915Smsmith * Parse the current state of the thermal zone and build control 189133624Snjl * structures. We don't need to worry about interference with the 190133624Snjl * control thread since we haven't fully attached this device yet. 19178915Smsmith */ 19278915Smsmith if ((error = acpi_tz_establish(sc)) != 0) 193133624Snjl return (error); 194133624Snjl 19578915Smsmith /* 19678915Smsmith * Register for any Notify events sent to this zone. 19778915Smsmith */ 19871874Smsmith AcpiInstallNotifyHandler(sc->tz_handle, ACPI_DEVICE_NOTIFY, 19978999Smsmith acpi_tz_notify_handler, sc); 20070271Stakawata 20171874Smsmith /* 20279283Smsmith * Create our sysctl nodes. 20379283Smsmith * 20479283Smsmith * XXX we need a mechanism for adding nodes under ACPI. 20579283Smsmith */ 20679283Smsmith if (device_get_unit(dev) == 0) { 20779283Smsmith acpi_sc = acpi_device_get_parent_softc(dev); 20879283Smsmith sysctl_ctx_init(&acpi_tz_sysctl_ctx); 20979283Smsmith acpi_tz_sysctl_tree = SYSCTL_ADD_NODE(&acpi_tz_sysctl_ctx, 210119529Snjl SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), 211119529Snjl OID_AUTO, "thermal", CTLFLAG_RD, 0, ""); 21285699Siwasaki SYSCTL_ADD_INT(&acpi_tz_sysctl_ctx, 21385699Siwasaki SYSCTL_CHILDREN(acpi_tz_sysctl_tree), 21485699Siwasaki OID_AUTO, "min_runtime", CTLFLAG_RD | CTLFLAG_RW, 215119529Snjl &acpi_tz_min_runtime, 0, 216119529Snjl "minimum cooling run time in sec"); 21788420Siwasaki SYSCTL_ADD_INT(&acpi_tz_sysctl_ctx, 21888420Siwasaki SYSCTL_CHILDREN(acpi_tz_sysctl_tree), 21988420Siwasaki OID_AUTO, "polling_rate", CTLFLAG_RD | CTLFLAG_RW, 22088420Siwasaki &acpi_tz_polling_rate, 0, "monitor polling rate"); 22179283Smsmith } 22279283Smsmith sysctl_ctx_init(&sc->tz_sysctl_ctx); 22379283Smsmith sprintf(oidname, "tz%d", device_get_unit(dev)); 22479283Smsmith sc->tz_sysctl_tree = SYSCTL_ADD_NODE(&sc->tz_sysctl_ctx, 225119529Snjl SYSCTL_CHILDREN(acpi_tz_sysctl_tree), 226119529Snjl OID_AUTO, oidname, CTLFLAG_RD, 0, ""); 227134541Speter SYSCTL_ADD_OPAQUE(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 228134541Speter OID_AUTO, "temperature", CTLFLAG_RD, &sc->tz_temperature, 229134961Snjl sizeof(sc->tz_temperature), "IK", 230134961Snjl "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"); 23886399Siwasaki SYSCTL_ADD_OPAQUE(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 239134961Snjl OID_AUTO, "_PSV", CTLFLAG_RD, &sc->tz_zone.psv, 240134961Snjl sizeof(sc->tz_zone.psv), "IK", ""); 241134961Snjl 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 48978915Smsmith/* 49078915Smsmith * Given an object, verify that it's a reference to a device of some sort, 49178915Smsmith * and try to switch it off. 49278915Smsmith */ 49378915Smsmithstatic void 49478915Smsmithacpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg) 49578915Smsmith{ 496128047Snjl ACPI_HANDLE cooler; 49778915Smsmith 49896926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 49978915Smsmith 500128047Snjl cooler = acpi_GetReference(NULL, obj); 501128047Snjl if (cooler == NULL) { 502128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get handle\n")); 503128047Snjl return_VOID; 504128047Snjl } 505102470Siwasaki 506128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s off\n", 507128047Snjl acpi_name(cooler))); 508128150Snjl acpi_pwr_switch_consumer(cooler, ACPI_STATE_D3); 509119529Snjl 51079375Smsmith return_VOID; 51178915Smsmith} 51278915Smsmith 51378915Smsmith/* 51478915Smsmith * Given an object, verify that it's a reference to a device of some sort, 51578915Smsmith * and try to switch it on. 51678915Smsmith * 517128047Snjl * XXX replication of off/on function code is bad. 51878915Smsmith */ 51978915Smsmithstatic void 52078915Smsmithacpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg) 52178915Smsmith{ 52278915Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg; 52378999Smsmith ACPI_HANDLE cooler; 52479375Smsmith ACPI_STATUS status; 52579375Smsmith 52696926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 52778915Smsmith 528128047Snjl cooler = acpi_GetReference(NULL, obj); 529128047Snjl if (cooler == NULL) { 530128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get handle\n")); 531128047Snjl return_VOID; 532128047Snjl } 533102470Siwasaki 534128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s on\n", 535128047Snjl acpi_name(cooler))); 536128047Snjl status = acpi_pwr_switch_consumer(cooler, ACPI_STATE_D0); 537128047Snjl if (ACPI_FAILURE(status)) { 538128047Snjl ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 539128047Snjl "failed to activate %s - %s\n", acpi_name(cooler), 540128047Snjl AcpiFormatException(status)); 54178915Smsmith } 542119529Snjl 543119529Snjl return_VOID; 54478915Smsmith} 54578915Smsmith 54678915Smsmith/* 54778915Smsmith * Read/debug-print a parameter, default it to -1. 54878915Smsmith */ 54978915Smsmithstatic void 55078915Smsmithacpi_tz_getparam(struct acpi_tz_softc *sc, char *node, int *data) 55178915Smsmith{ 55278915Smsmith 55396926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 55478915Smsmith 555126560Snjl if (ACPI_FAILURE(acpi_GetInteger(sc->tz_handle, node, data))) { 55678915Smsmith *data = -1; 55778915Smsmith } else { 558119529Snjl ACPI_DEBUG_PRINT((ACPI_DB_VALUES, "%s.%s = %d\n", 559119529Snjl acpi_name(sc->tz_handle), node, *data)); 56078915Smsmith } 561119529Snjl 56278915Smsmith return_VOID; 56378915Smsmith} 56479283Smsmith 56579283Smsmith/* 56679283Smsmith * Sanity-check a temperature value. Assume that setpoints 56779283Smsmith * should be between 0C and 150C. 56879283Smsmith */ 56979283Smsmithstatic void 57079283Smsmithacpi_tz_sanity(struct acpi_tz_softc *sc, int *val, char *what) 57179283Smsmith{ 572119529Snjl if (*val != -1 && (*val < TZ_ZEROC || *val > TZ_ZEROC + 1500)) { 57379283Smsmith device_printf(sc->tz_dev, "%s value is absurd, ignored (%d.%dC)\n", 57479283Smsmith what, TZ_KELVTOC(*val)); 57579283Smsmith *val = -1; 57679283Smsmith } 57779283Smsmith} 57879375Smsmith 57979375Smsmith/* 58079375Smsmith * Respond to a sysctl on the active state node. 58179375Smsmith */ 58279375Smsmithstatic int 58379375Smsmithacpi_tz_active_sysctl(SYSCTL_HANDLER_ARGS) 58479375Smsmith{ 58579375Smsmith struct acpi_tz_softc *sc; 58679375Smsmith int active; 58779375Smsmith int error; 58879375Smsmith 58979375Smsmith sc = (struct acpi_tz_softc *)oidp->oid_arg1; 59079375Smsmith active = sc->tz_active; 59179375Smsmith error = sysctl_handle_int(oidp, &active, 0, req); 59279375Smsmith 593119529Snjl /* Error or no new value */ 594119529Snjl if (error != 0 || req->newptr == NULL) 595133624Snjl return (error); 596133624Snjl if (active < -1 || active >= TZ_NUMLEVELS) 597133624Snjl return (EINVAL); 59879375Smsmith 599119529Snjl /* Set new preferred level and re-switch */ 60079375Smsmith sc->tz_requested = active; 601133624Snjl acpi_tz_signal(sc, 0); 602133624Snjl return (0); 60379375Smsmith} 60479375Smsmith 60578915Smsmithstatic void 60671874Smsmithacpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context) 60771874Smsmith{ 60878915Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)context; 60978915Smsmith 61096926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 61170271Stakawata 612133624Snjl switch (notify) { 61378915Smsmith case TZ_NOTIFY_TEMPERATURE: 614119529Snjl /* Temperature change occurred */ 615133624Snjl acpi_tz_signal(sc, 0); 61678915Smsmith break; 61778915Smsmith case TZ_NOTIFY_DEVICES: 61878915Smsmith case TZ_NOTIFY_LEVELS: 619119529Snjl /* Zone devices/setpoints changed */ 620133624Snjl acpi_tz_signal(sc, TZ_FLAG_GETSETTINGS); 62178915Smsmith break; 62278915Smsmith default: 62386552Siwasaki ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 624119529Snjl "unknown Notify event 0x%x\n", notify); 62578915Smsmith break; 62671874Smsmith } 627119529Snjl 628121493Snjl acpi_UserNotify("Thermal", h, notify); 629121493Snjl 63071874Smsmith return_VOID; 63171874Smsmith} 63270271Stakawata 633133624Snjlstatic void 634133624Snjlacpi_tz_signal(struct acpi_tz_softc *sc, int flags) 635133624Snjl{ 636133624Snjl ACPI_LOCK(thermal); 637133624Snjl sc->tz_flags |= flags; 638133624Snjl ACPI_UNLOCK(thermal); 639133624Snjl wakeup(&acpi_tz_proc); 640133624Snjl} 641133624Snjl 64278915Smsmith/* 643134909Snjl * Notifies can be generated asynchronously but have also been seen to be 644134909Snjl * triggered by other thermal methods. One system generates a notify of 645134909Snjl * 0x81 when the fan is turned on or off. Another generates it when _SCP 646134909Snjl * is called. To handle these situations, we check the zone via 647134909Snjl * acpi_tz_monitor() before evaluating changes to setpoints or the cooling 648134909Snjl * policy. 64978915Smsmith */ 65078915Smsmithstatic void 651133624Snjlacpi_tz_timeout(struct acpi_tz_softc *sc, int flags) 65278915Smsmith{ 653134909Snjl 654134909Snjl /* Check the current temperature and take action based on it */ 655134909Snjl acpi_tz_monitor(sc); 656134909Snjl 657133624Snjl /* If requested, get the power profile settings. */ 658133624Snjl if (flags & TZ_FLAG_GETPROFILE) 659133624Snjl acpi_tz_power_profile(sc); 66079375Smsmith 661134909Snjl /* 662134909Snjl * If requested, check for new devices/setpoints. After finding them, 663134909Snjl * check if we need to switch fans based on the new values. 664134909Snjl */ 665134909Snjl if (flags & TZ_FLAG_GETSETTINGS) { 666133624Snjl acpi_tz_establish(sc); 667134909Snjl acpi_tz_monitor(sc); 668134909Snjl } 66978915Smsmith 67078915Smsmith /* XXX passive cooling actions? */ 67178915Smsmith} 67279375Smsmith 67379375Smsmith/* 67479375Smsmith * System power profile may have changed; fetch and notify the 67579375Smsmith * thermal zone accordingly. 67679375Smsmith * 67779375Smsmith * Since this can be called from an arbitrary eventhandler, it needs 67879375Smsmith * to get the ACPI lock itself. 67979375Smsmith */ 68079375Smsmithstatic void 68191640Siwasakiacpi_tz_power_profile(void *arg) 68279375Smsmith{ 68379375Smsmith ACPI_STATUS status; 68479375Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg; 68591640Siwasaki int state; 68679375Smsmith 68791640Siwasaki state = power_profile_get_state(); 688119529Snjl if (state != POWER_PROFILE_PERFORMANCE && state != POWER_PROFILE_ECONOMY) 689119529Snjl return; 69091640Siwasaki 69179375Smsmith /* check that we haven't decided there's no _SCP method */ 692119529Snjl if ((sc->tz_flags & TZ_FLAG_NO_SCP) == 0) { 69379375Smsmith 694119529Snjl /* Call _SCP to set the new profile */ 695126560Snjl status = acpi_SetInteger(sc->tz_handle, "_SCP", 696126560Snjl (state == POWER_PROFILE_PERFORMANCE) ? 0 : 1); 697119529Snjl if (ACPI_FAILURE(status)) { 69879385Smsmith if (status != AE_NOT_FOUND) 699119529Snjl ACPI_VPRINT(sc->tz_dev, 700119529Snjl acpi_device_get_parent_softc(sc->tz_dev), 701119529Snjl "can't evaluate %s._SCP - %s\n", 702119529Snjl acpi_name(sc->tz_handle), 703119529Snjl AcpiFormatException(status)); 70479375Smsmith sc->tz_flags |= TZ_FLAG_NO_SCP; 70579375Smsmith } else { 706119529Snjl /* We have to re-evaluate the entire zone now */ 707133624Snjl acpi_tz_signal(sc, TZ_FLAG_GETSETTINGS); 70879375Smsmith } 70979375Smsmith } 71079375Smsmith} 71179375Smsmith 71291126Smsmith/* 71391126Smsmith * Thermal zone monitor thread. 71491126Smsmith */ 71591126Smsmithstatic void 71691126Smsmithacpi_tz_thread(void *arg) 71791126Smsmith{ 71891126Smsmith device_t *devs; 71991126Smsmith int devcount, i; 720133624Snjl int flags; 721133624Snjl struct acpi_tz_softc **sc; 72291126Smsmith 72396926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 72491126Smsmith 72591126Smsmith devs = NULL; 72691126Smsmith devcount = 0; 727133624Snjl sc = NULL; 72891126Smsmith 72991126Smsmith for (;;) { 730133624Snjl /* If the number of devices has changed, re-evaluate. */ 731133624Snjl if (devclass_get_maxunit(acpi_tz_devclass) != devcount) { 732133624Snjl if (devs != NULL) { 733133624Snjl free(devs, M_TEMP); 734133624Snjl free(sc, M_TEMP); 735133624Snjl } 736133624Snjl devclass_get_devices(acpi_tz_devclass, &devs, &devcount); 737133624Snjl sc = malloc(sizeof(struct acpi_tz_softc *) * devcount, M_TEMP, 738133624Snjl M_WAITOK | M_ZERO); 739133624Snjl for (i = 0; i < devcount; i++) 740133624Snjl sc[i] = device_get_softc(devs[i]); 741133624Snjl } 74291126Smsmith 743133624Snjl /* Check for temperature events and act on them. */ 744133624Snjl for (i = 0; i < devcount; i++) { 745133624Snjl ACPI_LOCK(thermal); 746133624Snjl flags = sc[i]->tz_flags; 747133624Snjl sc[i]->tz_flags &= TZ_FLAG_NO_SCP; 748133624Snjl ACPI_UNLOCK(thermal); 749133624Snjl acpi_tz_timeout(sc[i], flags); 750133624Snjl } 75191215Smsmith 752133624Snjl /* If more work to do, don't go to sleep yet. */ 753133624Snjl ACPI_LOCK(thermal); 754133624Snjl for (i = 0; i < devcount; i++) { 755133624Snjl if (sc[i]->tz_flags & ~TZ_FLAG_NO_SCP) 756133624Snjl break; 757133624Snjl } 75891126Smsmith 759133624Snjl /* 760133624Snjl * If we have no more work, sleep for a while, setting PDROP so that 761133624Snjl * the mutex will not be reacquired. Otherwise, drop the mutex and 762133624Snjl * loop to handle more events. 763133624Snjl */ 764133624Snjl if (i == devcount) 765133624Snjl msleep(&acpi_tz_proc, &thermal_mutex, PZERO | PDROP, "tzpoll", 766133624Snjl hz * acpi_tz_polling_rate); 767133624Snjl else 768133624Snjl ACPI_UNLOCK(thermal); 76991126Smsmith } 77091126Smsmith} 771