acpi_thermal.c revision 128047
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 128047 2004-04-09 06:55:50Z njl $"); 30119418Sobrien 3167761Smsmith#include "opt_acpi.h" 3267761Smsmith#include <sys/param.h> 3367761Smsmith#include <sys/kernel.h> 3491126Smsmith#include <sys/kthread.h> 3567761Smsmith#include <sys/bus.h> 3691126Smsmith#include <sys/proc.h> 3778915Smsmith#include <sys/reboot.h> 3879283Smsmith#include <sys/sysctl.h> 3991126Smsmith#include <sys/unistd.h> 4091640Siwasaki#include <sys/power.h> 4167761Smsmith 4267761Smsmith#include "acpi.h" 4367761Smsmith#include <dev/acpica/acpivar.h> 4467761Smsmith 45119529Snjl/* Hooks for the ACPI CA debugging infrastructure */ 4678999Smsmith#define _COMPONENT ACPI_THERMAL 4791126SmsmithACPI_MODULE_NAME("THERMAL") 4869744Smsmith 4971874Smsmith#define TZ_ZEROC 2732 5071874Smsmith#define TZ_KELVTOC(x) (((x) - TZ_ZEROC) / 10), (((x) - TZ_ZEROC) % 10) 5167761Smsmith 52125366Snjl#define TZ_NOTIFY_TEMPERATURE 0x80 /* Temperature changed. */ 53125366Snjl#define TZ_NOTIFY_LEVELS 0x81 /* Cooling levels changed. */ 54125366Snjl#define TZ_NOTIFY_DEVICES 0x82 /* Device lists changed. */ 55125366Snjl#define TZ_NOTIFY_CRITICAL 0xcc /* Fake notify that _CRT/_HOT reached. */ 5678915Smsmith 57125335Snjl/* Check for temperature changes every 10 seconds by default */ 58125335Snjl#define TZ_POLLRATE 10 5978915Smsmith 60125335Snjl/* Make sure the reported temperature is valid for this number of polls. */ 61125335Snjl#define TZ_VALIDCHECKS 3 62125335Snjl 63125366Snjl/* Notify the user we will be shutting down in one more poll cycle. */ 64125366Snjl#define TZ_NOTIFYCOUNT (TZ_VALIDCHECKS - 1) 65125366Snjl 66119529Snjl/* ACPI spec defines this */ 67119529Snjl#define TZ_NUMLEVELS 10 6879375Smsmithstruct acpi_tz_zone { 6978915Smsmith int ac[TZ_NUMLEVELS]; 7078915Smsmith ACPI_BUFFER al[TZ_NUMLEVELS]; 7178915Smsmith int crt; 7278915Smsmith int hot; 7378915Smsmith ACPI_BUFFER psl; 7478915Smsmith int psv; 7578915Smsmith int tc1; 7678915Smsmith int tc2; 7778915Smsmith int tsp; 7878915Smsmith int tzp; 7978915Smsmith}; 8078915Smsmith 8167761Smsmithstruct acpi_tz_softc { 82119529Snjl device_t tz_dev; 83119529Snjl ACPI_HANDLE tz_handle; /*Thermal zone handle*/ 84119529Snjl int tz_temperature; /*Current temperature*/ 85119529Snjl int tz_active; /*Current active cooling*/ 8679375Smsmith#define TZ_ACTIVE_NONE -1 87119529Snjl int tz_requested; /*Minimum active cooling*/ 88119529Snjl int tz_thflags; /*Current temp-related flags*/ 8979375Smsmith#define TZ_THFLAG_NONE 0 9079375Smsmith#define TZ_THFLAG_PSV (1<<0) 9179375Smsmith#define TZ_THFLAG_HOT (1<<2) 9279375Smsmith#define TZ_THFLAG_CRT (1<<3) 9379283Smsmith int tz_flags; 94119529Snjl#define TZ_FLAG_NO_SCP (1<<0) /*No _SCP method*/ 95119529Snjl#define TZ_FLAG_GETPROFILE (1<<1) /*Get power_profile in timeout*/ 96119529Snjl struct timespec tz_cooling_started; 97119529Snjl /*Current cooling starting time*/ 9879283Smsmith 99119529Snjl struct sysctl_ctx_list tz_sysctl_ctx; 10079283Smsmith struct sysctl_oid *tz_sysctl_tree; 10178915Smsmith 102119529Snjl struct acpi_tz_zone tz_zone; /*Thermal zone parameters*/ 10388420Siwasaki int tz_tmp_updating; 104125335Snjl int tz_validchecks; 10567761Smsmith}; 10667761Smsmith 10767761Smsmithstatic int acpi_tz_probe(device_t dev); 10867761Smsmithstatic int acpi_tz_attach(device_t dev); 10978915Smsmithstatic int acpi_tz_establish(struct acpi_tz_softc *sc); 110119529Snjlstatic void acpi_tz_monitor(void *Context); 11178915Smsmithstatic void acpi_tz_all_off(struct acpi_tz_softc *sc); 11278915Smsmithstatic void acpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg); 11378915Smsmithstatic void acpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg); 114119529Snjlstatic void acpi_tz_getparam(struct acpi_tz_softc *sc, char *node, 115119529Snjl int *data); 11679283Smsmithstatic void acpi_tz_sanity(struct acpi_tz_softc *sc, int *val, char *what); 11779375Smsmithstatic int acpi_tz_active_sysctl(SYSCTL_HANDLER_ARGS); 118119529Snjlstatic void acpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, 119119529Snjl void *context); 12091126Smsmithstatic void acpi_tz_timeout(struct acpi_tz_softc *sc); 12191640Siwasakistatic void acpi_tz_power_profile(void *arg); 12291126Smsmithstatic void acpi_tz_thread(void *arg); 12391126Smsmith 12467761Smsmithstatic device_method_t acpi_tz_methods[] = { 12567761Smsmith /* Device interface */ 12667761Smsmith DEVMETHOD(device_probe, acpi_tz_probe), 12767761Smsmith DEVMETHOD(device_attach, acpi_tz_attach), 12867761Smsmith 12967761Smsmith {0, 0} 13067761Smsmith}; 13167761Smsmith 13267761Smsmithstatic driver_t acpi_tz_driver = { 13367761Smsmith "acpi_tz", 13467761Smsmith acpi_tz_methods, 13567761Smsmith sizeof(struct acpi_tz_softc), 13667761Smsmith}; 13767761Smsmith 13889054Smsmithstatic devclass_t acpi_tz_devclass; 13967761SmsmithDRIVER_MODULE(acpi_tz, acpi, acpi_tz_driver, acpi_tz_devclass, 0, 0); 14067761Smsmith 14179283Smsmithstatic struct sysctl_ctx_list acpi_tz_sysctl_ctx; 14279283Smsmithstatic struct sysctl_oid *acpi_tz_sysctl_tree; 14379283Smsmith 144119529Snjl/* Minimum cooling run time */ 145119529Snjlstatic int acpi_tz_min_runtime = 0; 14688420Siwasakistatic int acpi_tz_polling_rate = TZ_POLLRATE; 14785699Siwasaki 148119529Snjl/* Timezone polling thread */ 149119529Snjlstatic struct proc *acpi_tz_proc; 150119529Snjl 15178915Smsmith/* 15278915Smsmith * Match an ACPI thermal zone. 15378915Smsmith */ 15467761Smsmithstatic int 15567761Smsmithacpi_tz_probe(device_t dev) 15667761Smsmith{ 15778999Smsmith int result; 158105282Sjhb ACPI_LOCK_DECL; 15978999Smsmith 16078999Smsmith ACPI_LOCK; 16178999Smsmith 162119529Snjl /* No FUNCTION_TRACE - too noisy */ 16369744Smsmith 164119529Snjl if (acpi_get_type(dev) == ACPI_TYPE_THERMAL && !acpi_disabled("thermal")) { 165120453Snjl device_set_desc(dev, "Thermal Zone"); 16678999Smsmith result = -10; 16778999Smsmith } else { 16878999Smsmith result = ENXIO; 16967761Smsmith } 17078999Smsmith ACPI_UNLOCK; 171119529Snjl return (result); 17267761Smsmith} 17367761Smsmith 17478915Smsmith/* 17578915Smsmith * Attach to an ACPI thermal zone. 17678915Smsmith */ 17767761Smsmithstatic int 17867761Smsmithacpi_tz_attach(device_t dev) 17967761Smsmith{ 18067761Smsmith struct acpi_tz_softc *sc; 18179283Smsmith struct acpi_softc *acpi_sc; 18278915Smsmith int error; 18379283Smsmith char oidname[8]; 184105282Sjhb ACPI_LOCK_DECL; 18567761Smsmith 18696926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 18769744Smsmith 18878999Smsmith ACPI_LOCK; 18978999Smsmith 19067761Smsmith sc = device_get_softc(dev); 19167761Smsmith sc->tz_dev = dev; 19267761Smsmith sc->tz_handle = acpi_get_handle(dev); 19379375Smsmith sc->tz_requested = TZ_ACTIVE_NONE; 19488420Siwasaki sc->tz_tmp_updating = 0; 19567761Smsmith 19678915Smsmith /* 19778915Smsmith * Parse the current state of the thermal zone and build control 19878915Smsmith * structures. 19978915Smsmith */ 20078915Smsmith if ((error = acpi_tz_establish(sc)) != 0) 20178999Smsmith goto out; 20278915Smsmith 20378915Smsmith /* 204126388Snjl * XXX Call _INI if it exists. ACPICA should do this but only handles 205126388Snjl * Device objects for now. 206126388Snjl */ 207126388Snjl AcpiEvaluateObject(sc->tz_handle, "_INI", NULL, NULL); 208126388Snjl 209126388Snjl /* 21078915Smsmith * Register for any Notify events sent to this zone. 21178915Smsmith */ 21271874Smsmith AcpiInstallNotifyHandler(sc->tz_handle, ACPI_DEVICE_NOTIFY, 21378999Smsmith acpi_tz_notify_handler, sc); 21470271Stakawata 21571874Smsmith /* 21679283Smsmith * Create our sysctl nodes. 21779283Smsmith * 21879283Smsmith * XXX we need a mechanism for adding nodes under ACPI. 21979283Smsmith */ 22079283Smsmith if (device_get_unit(dev) == 0) { 22179283Smsmith acpi_sc = acpi_device_get_parent_softc(dev); 22279283Smsmith sysctl_ctx_init(&acpi_tz_sysctl_ctx); 22379283Smsmith acpi_tz_sysctl_tree = SYSCTL_ADD_NODE(&acpi_tz_sysctl_ctx, 224119529Snjl SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), 225119529Snjl OID_AUTO, "thermal", CTLFLAG_RD, 0, ""); 22685699Siwasaki SYSCTL_ADD_INT(&acpi_tz_sysctl_ctx, 22785699Siwasaki SYSCTL_CHILDREN(acpi_tz_sysctl_tree), 22885699Siwasaki OID_AUTO, "min_runtime", CTLFLAG_RD | CTLFLAG_RW, 229119529Snjl &acpi_tz_min_runtime, 0, 230119529Snjl "minimum cooling run time in sec"); 23188420Siwasaki SYSCTL_ADD_INT(&acpi_tz_sysctl_ctx, 23288420Siwasaki SYSCTL_CHILDREN(acpi_tz_sysctl_tree), 23388420Siwasaki OID_AUTO, "polling_rate", CTLFLAG_RD | CTLFLAG_RW, 23488420Siwasaki &acpi_tz_polling_rate, 0, "monitor polling rate"); 23579283Smsmith } 23679283Smsmith sysctl_ctx_init(&sc->tz_sysctl_ctx); 23779283Smsmith sprintf(oidname, "tz%d", device_get_unit(dev)); 23879283Smsmith sc->tz_sysctl_tree = SYSCTL_ADD_NODE(&sc->tz_sysctl_ctx, 239119529Snjl SYSCTL_CHILDREN(acpi_tz_sysctl_tree), 240119529Snjl OID_AUTO, oidname, CTLFLAG_RD, 0, ""); 24179283Smsmith SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 24279283Smsmith OID_AUTO, "temperature", CTLFLAG_RD, 24379283Smsmith &sc->tz_temperature, 0, "current thermal zone temperature"); 24479375Smsmith SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 24579375Smsmith OID_AUTO, "active", CTLTYPE_INT | CTLFLAG_RW, 24679375Smsmith sc, 0, acpi_tz_active_sysctl, "I", ""); 24779375Smsmith 24879283Smsmith SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 24979375Smsmith OID_AUTO, "thermal_flags", CTLFLAG_RD, 25079375Smsmith &sc->tz_thflags, 0, "thermal zone flags"); 25179283Smsmith SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 25279283Smsmith OID_AUTO, "_PSV", CTLFLAG_RD, 25379375Smsmith &sc->tz_zone.psv, 0, ""); 25479283Smsmith SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 25579283Smsmith OID_AUTO, "_HOT", CTLFLAG_RD, 25679375Smsmith &sc->tz_zone.hot, 0, ""); 25779283Smsmith SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 25879283Smsmith OID_AUTO, "_CRT", CTLFLAG_RD, 25979375Smsmith &sc->tz_zone.crt, 0, ""); 26086399Siwasaki SYSCTL_ADD_OPAQUE(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 26186399Siwasaki OID_AUTO, "_ACx", CTLFLAG_RD, &sc->tz_zone.ac, 26286399Siwasaki sizeof(sc->tz_zone.ac), "I", ""); 26379283Smsmith 26479283Smsmith /* 26579375Smsmith * Register our power profile event handler, and flag it for a manual 26679375Smsmith * invocation by our timeout. We defer it like this so that the rest 26779375Smsmith * of the subsystem has time to come up. 26879375Smsmith */ 26991640Siwasaki EVENTHANDLER_REGISTER(power_profile_change, acpi_tz_power_profile, sc, 0); 27079375Smsmith sc->tz_flags |= TZ_FLAG_GETPROFILE; 27179375Smsmith 27279375Smsmith /* 27371874Smsmith * Don't bother evaluating/printing the temperature at this point; 27471874Smsmith * on many systems it'll be bogus until the EC is running. 27571874Smsmith */ 27678999Smsmith 27791126Smsmith /* 27891126Smsmith * Create our thread; we only need one, it will service all of the 27991126Smsmith * thermal zones. 28091126Smsmith */ 28191126Smsmith if (acpi_tz_proc == NULL) { 28291126Smsmith error = kthread_create(acpi_tz_thread, NULL, &acpi_tz_proc, 283104354Sscottl RFHIGHPID, 0, "acpi_thermal"); 28491126Smsmith if (error != 0) { 285119529Snjl device_printf(sc->tz_dev, "could not create thread - %d", 286119529Snjl error); 28791126Smsmith goto out; 28891126Smsmith } 28991126Smsmith } 29091126Smsmith 29178999Smsmith out: 29278999Smsmith ACPI_UNLOCK; 29379375Smsmith 294119529Snjl return_VALUE (error); 29567761Smsmith} 29670271Stakawata 29778915Smsmith/* 29878915Smsmith * Parse the current state of this thermal zone and set up to use it. 29978915Smsmith * 30078915Smsmith * Note that we may have previous state, which will have to be discarded. 30178915Smsmith */ 30278915Smsmithstatic int 30378915Smsmithacpi_tz_establish(struct acpi_tz_softc *sc) 30478915Smsmith{ 30578915Smsmith ACPI_OBJECT *obj; 30678915Smsmith int i; 30778915Smsmith char nbuf[8]; 30878915Smsmith 30996926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 31078915Smsmith 31178999Smsmith ACPI_ASSERTLOCK; 31278999Smsmith 313119529Snjl /* Power everything off and erase any existing state. */ 31478915Smsmith acpi_tz_all_off(sc); 31578915Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) 31679375Smsmith if (sc->tz_zone.al[i].Pointer != NULL) 31779375Smsmith AcpiOsFree(sc->tz_zone.al[i].Pointer); 31879375Smsmith if (sc->tz_zone.psl.Pointer != NULL) 31979375Smsmith AcpiOsFree(sc->tz_zone.psl.Pointer); 32079375Smsmith bzero(&sc->tz_zone, sizeof(sc->tz_zone)); 32178915Smsmith 322119529Snjl /* Evaluate thermal zone parameters. */ 32378915Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) { 32478915Smsmith sprintf(nbuf, "_AC%d", i); 32579375Smsmith acpi_tz_getparam(sc, nbuf, &sc->tz_zone.ac[i]); 32678915Smsmith sprintf(nbuf, "_AL%d", i); 32791126Smsmith sc->tz_zone.al[i].Length = ACPI_ALLOCATE_BUFFER; 32891126Smsmith sc->tz_zone.al[i].Pointer = NULL; 32991126Smsmith AcpiEvaluateObject(sc->tz_handle, nbuf, NULL, &sc->tz_zone.al[i]); 33079375Smsmith obj = (ACPI_OBJECT *)sc->tz_zone.al[i].Pointer; 33178915Smsmith if (obj != NULL) { 332119529Snjl /* Should be a package containing a list of power objects */ 33378915Smsmith if (obj->Type != ACPI_TYPE_PACKAGE) { 334119529Snjl device_printf(sc->tz_dev, "%s has unknown type %d, rejecting\n", 33578915Smsmith nbuf, obj->Type); 336119529Snjl return_VALUE (ENXIO); 33778915Smsmith } 33878915Smsmith } 33978915Smsmith } 34079375Smsmith acpi_tz_getparam(sc, "_CRT", &sc->tz_zone.crt); 34179375Smsmith acpi_tz_getparam(sc, "_HOT", &sc->tz_zone.hot); 34291126Smsmith sc->tz_zone.psl.Length = ACPI_ALLOCATE_BUFFER; 34391126Smsmith sc->tz_zone.psl.Pointer = NULL; 34491126Smsmith AcpiEvaluateObject(sc->tz_handle, "_PSL", NULL, &sc->tz_zone.psl); 34579375Smsmith acpi_tz_getparam(sc, "_PSV", &sc->tz_zone.psv); 34679375Smsmith acpi_tz_getparam(sc, "_TC1", &sc->tz_zone.tc1); 34779375Smsmith acpi_tz_getparam(sc, "_TC2", &sc->tz_zone.tc2); 34879375Smsmith acpi_tz_getparam(sc, "_TSP", &sc->tz_zone.tsp); 34979375Smsmith acpi_tz_getparam(sc, "_TZP", &sc->tz_zone.tzp); 35078915Smsmith 35178915Smsmith /* 35279283Smsmith * Sanity-check the values we've been given. 35379283Smsmith * 35479283Smsmith * XXX what do we do about systems that give us the same value for 35579283Smsmith * more than one of these setpoints? 35679283Smsmith */ 35779375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.crt, "_CRT"); 35879375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.hot, "_HOT"); 35979375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.psv, "_PSV"); 36079283Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) 36179375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.ac[i], "_ACx"); 36279283Smsmith 36379283Smsmith /* 36478915Smsmith * Power off everything that we've just been given. 36578915Smsmith */ 36678915Smsmith acpi_tz_all_off(sc); 36778915Smsmith 368119529Snjl return_VALUE (0); 36978915Smsmith} 37078915Smsmith 37185699Siwasakistatic char *aclevel_string[] = { 37285699Siwasaki "NONE", "_AC0", "_AC1", "_AC2", "_AC3", "_AC4", 37385699Siwasaki "_AC5", "_AC6", "_AC7", "_AC8", "_AC9" }; 37485699Siwasaki 37585699Siwasakistatic __inline const char * 37685699Siwasakiacpi_tz_aclevel_string(int active) 37785699Siwasaki{ 378119529Snjl if (active < -1 || active >= TZ_NUMLEVELS) 37985699Siwasaki return (aclevel_string[0]); 38085699Siwasaki 38185699Siwasaki return (aclevel_string[active+1]); 38285699Siwasaki} 38385699Siwasaki 38478915Smsmith/* 38578915Smsmith * Evaluate the condition of a thermal zone, take appropriate actions. 38678915Smsmith */ 38771874Smsmithstatic void 388119529Snjlacpi_tz_monitor(void *Context) 38971874Smsmith{ 390119529Snjl struct acpi_tz_softc *sc; 391119529Snjl struct timespec curtime; 39279283Smsmith int temp; 39378915Smsmith int i; 39479283Smsmith int newactive, newflags; 39586399Siwasaki ACPI_STATUS status; 39670271Stakawata 39796926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 39870271Stakawata 39978999Smsmith ACPI_ASSERTLOCK; 40078999Smsmith 401119529Snjl sc = (struct acpi_tz_softc *)Context; 402119529Snjl if (sc->tz_tmp_updating) 40388420Siwasaki goto out; 40488420Siwasaki sc->tz_tmp_updating = 1; 40588420Siwasaki 406119529Snjl /* Get the current temperature. */ 407126560Snjl status = acpi_GetInteger(sc->tz_handle, "_TMP", &temp); 408119529Snjl if (ACPI_FAILURE(status)) { 40986552Siwasaki ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 41086552Siwasaki "error fetching current temperature -- %s\n", 41186552Siwasaki AcpiFormatException(status)); 41278915Smsmith /* XXX disable zone? go to max cooling? */ 41388420Siwasaki goto out; 41471874Smsmith } 41588420Siwasaki 41682372Smsmith ACPI_DEBUG_PRINT((ACPI_DB_VALUES, "got %d.%dC\n", TZ_KELVTOC(temp))); 41779283Smsmith sc->tz_temperature = temp; 41878915Smsmith 41978915Smsmith /* 42078915Smsmith * Work out what we ought to be doing right now. 42179283Smsmith * 42279283Smsmith * Note that the _ACx levels sort from hot to cold. 42378915Smsmith */ 42479283Smsmith newactive = TZ_ACTIVE_NONE; 42579375Smsmith for (i = TZ_NUMLEVELS - 1; i >= 0; i--) { 42679375Smsmith if ((sc->tz_zone.ac[i] != -1) && (temp >= sc->tz_zone.ac[i])) { 42779283Smsmith newactive = i; 42882967Siwasaki if (sc->tz_active != newactive) { 429119529Snjl ACPI_VPRINT(sc->tz_dev, 430119529Snjl acpi_device_get_parent_softc(sc->tz_dev), 431119529Snjl "_AC%d: temperature %d.%d >= setpoint %d.%d\n", i, 432119529Snjl TZ_KELVTOC(temp), TZ_KELVTOC(sc->tz_zone.ac[i])); 43385699Siwasaki getnanotime(&sc->tz_cooling_started); 43482967Siwasaki } 43579375Smsmith } 43679375Smsmith } 43779283Smsmith 43885699Siwasaki /* 43985699Siwasaki * We are going to get _ACx level down (colder side), but give a guaranteed 44085699Siwasaki * minimum cooling run time if requested. 44185699Siwasaki */ 44285699Siwasaki if (acpi_tz_min_runtime > 0 && sc->tz_active != TZ_ACTIVE_NONE && 44385699Siwasaki (newactive == TZ_ACTIVE_NONE || newactive > sc->tz_active)) { 444119529Snjl 44585699Siwasaki getnanotime(&curtime); 44685699Siwasaki timespecsub(&curtime, &sc->tz_cooling_started); 447119529Snjl if (curtime.tv_sec < acpi_tz_min_runtime) 44885699Siwasaki newactive = sc->tz_active; 44985699Siwasaki } 45085699Siwasaki 451119529Snjl /* Handle user override of active mode */ 452126662Snjl if (sc->tz_requested != TZ_ACTIVE_NONE && sc->tz_requested < newactive) 45379375Smsmith newactive = sc->tz_requested; 45478915Smsmith 45579375Smsmith /* update temperature-related flags */ 45679375Smsmith newflags = TZ_THFLAG_NONE; 457124439Snjl if (sc->tz_zone.psv != -1 && temp >= sc->tz_zone.psv) 45879375Smsmith newflags |= TZ_THFLAG_PSV; 459124439Snjl if (sc->tz_zone.hot != -1 && temp >= sc->tz_zone.hot) 46079375Smsmith newflags |= TZ_THFLAG_HOT; 461124439Snjl if (sc->tz_zone.crt != -1 && temp >= sc->tz_zone.crt) 46279375Smsmith newflags |= TZ_THFLAG_CRT; 46379375Smsmith 464119529Snjl /* If the active cooling state has changed, we have to switch things. */ 46579283Smsmith if (newactive != sc->tz_active) { 466119529Snjl /* Turn off the cooling devices that are on, if any are */ 46779283Smsmith if (sc->tz_active != TZ_ACTIVE_NONE) 468119529Snjl acpi_ForeachPackageObject( 469119529Snjl (ACPI_OBJECT *)sc->tz_zone.al[sc->tz_active].Pointer, 470119529Snjl acpi_tz_switch_cooler_off, sc); 47178915Smsmith 472119529Snjl /* Turn on cooling devices that are required, if any are */ 473119529Snjl if (newactive != TZ_ACTIVE_NONE) { 474119529Snjl acpi_ForeachPackageObject( 475119529Snjl (ACPI_OBJECT *)sc->tz_zone.al[newactive].Pointer, 476119529Snjl acpi_tz_switch_cooler_on, sc); 477119529Snjl } 47886552Siwasaki ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 479119529Snjl "switched from %s to %s: %d.%dC\n", 480119529Snjl acpi_tz_aclevel_string(sc->tz_active), 481119529Snjl acpi_tz_aclevel_string(newactive), TZ_KELVTOC(temp)); 48279283Smsmith sc->tz_active = newactive; 48379283Smsmith } 48478915Smsmith 485119529Snjl /* XXX (de)activate any passive cooling that may be required. */ 48678915Smsmith 48778915Smsmith /* 488125335Snjl * If the temperature is at _HOT or _CRT, increment our event count. 489125335Snjl * If it has occurred enough times, shutdown the system. This is 490125335Snjl * needed because some systems will report an invalid high temperature 491125335Snjl * for one poll cycle. It is suspected this is due to the embedded 492125335Snjl * controller timing out. A typical value is 138C for one cycle on 493125335Snjl * a system that is otherwise 65C. 494125366Snjl * 495125366Snjl * If we're almost at that threshold, notify the user through devd(8). 49678915Smsmith */ 497125335Snjl if ((newflags & (TZ_THFLAG_HOT | TZ_THFLAG_CRT)) != 0) { 498125366Snjl sc->tz_validchecks++; 499125366Snjl if (sc->tz_validchecks == TZ_VALIDCHECKS) { 500125335Snjl device_printf(sc->tz_dev, 501125335Snjl "WARNING - current temperature (%d.%dC) exceeds safe limits\n", 502125335Snjl TZ_KELVTOC(sc->tz_temperature)); 503125335Snjl shutdown_nice(RB_POWEROFF); 504125366Snjl } else if (sc->tz_validchecks == TZ_NOTIFYCOUNT) 505125366Snjl acpi_UserNotify("Thermal", sc->tz_handle, TZ_NOTIFY_CRITICAL); 506125335Snjl } else { 507125335Snjl sc->tz_validchecks = 0; 50878915Smsmith } 50979375Smsmith sc->tz_thflags = newflags; 51078915Smsmith 51188420Siwasakiout: 51288420Siwasaki sc->tz_tmp_updating = 0; 51371874Smsmith return_VOID; 51471874Smsmith} 51570271Stakawata 51678915Smsmith/* 51778915Smsmith * Turn off all the cooling devices. 51878915Smsmith */ 51971874Smsmithstatic void 52078915Smsmithacpi_tz_all_off(struct acpi_tz_softc *sc) 52178915Smsmith{ 52278915Smsmith int i; 52378915Smsmith 52496926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 52578999Smsmith 52678999Smsmith ACPI_ASSERTLOCK; 52778915Smsmith 528119529Snjl /* Scan all the _ALx objects and turn them all off. */ 52978915Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) { 53079375Smsmith if (sc->tz_zone.al[i].Pointer == NULL) 53178915Smsmith continue; 53279375Smsmith acpi_ForeachPackageObject((ACPI_OBJECT *)sc->tz_zone.al[i].Pointer, 53378915Smsmith acpi_tz_switch_cooler_off, sc); 53478915Smsmith } 53578915Smsmith 53678915Smsmith /* 53778915Smsmith * XXX revert any passive-cooling options. 53878915Smsmith */ 53978915Smsmith 54079283Smsmith sc->tz_active = TZ_ACTIVE_NONE; 54179375Smsmith sc->tz_thflags = TZ_THFLAG_NONE; 542119529Snjl 54378915Smsmith return_VOID; 54478915Smsmith} 54578915Smsmith 54678915Smsmith/* 54778915Smsmith * Given an object, verify that it's a reference to a device of some sort, 54878915Smsmith * and try to switch it off. 54978915Smsmith */ 55078915Smsmithstatic void 55178915Smsmithacpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg) 55278915Smsmith{ 553128047Snjl struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg; 554128047Snjl ACPI_HANDLE cooler; 555128047Snjl ACPI_STATUS status; 55678915Smsmith 55796926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 55878915Smsmith 55978999Smsmith ACPI_ASSERTLOCK; 56078999Smsmith 561128047Snjl cooler = acpi_GetReference(NULL, obj); 562128047Snjl if (cooler == NULL) { 563128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get handle\n")); 564128047Snjl return_VOID; 565128047Snjl } 566102470Siwasaki 567128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s off\n", 568128047Snjl acpi_name(cooler))); 569128047Snjl status = acpi_pwr_switch_consumer(cooler, ACPI_STATE_D3); 570128047Snjl if (ACPI_FAILURE(status)) { 571128047Snjl ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 572128047Snjl "failed to deactivate %s - %s\n", acpi_name(cooler), 573128047Snjl AcpiFormatException(status)); 57478915Smsmith } 575119529Snjl 57679375Smsmith return_VOID; 57778915Smsmith} 57878915Smsmith 57978915Smsmith/* 58078915Smsmith * Given an object, verify that it's a reference to a device of some sort, 58178915Smsmith * and try to switch it on. 58278915Smsmith * 583128047Snjl * XXX replication of off/on function code is bad. 58478915Smsmith */ 58578915Smsmithstatic void 58678915Smsmithacpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg) 58778915Smsmith{ 58878915Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg; 58978999Smsmith ACPI_HANDLE cooler; 59079375Smsmith ACPI_STATUS status; 59179375Smsmith 59296926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 59378915Smsmith 59478999Smsmith ACPI_ASSERTLOCK; 59578999Smsmith 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 62378999Smsmith ACPI_ASSERTLOCK; 62478999Smsmith 625126560Snjl if (ACPI_FAILURE(acpi_GetInteger(sc->tz_handle, node, data))) { 62678915Smsmith *data = -1; 62778915Smsmith } else { 628119529Snjl ACPI_DEBUG_PRINT((ACPI_DB_VALUES, "%s.%s = %d\n", 629119529Snjl acpi_name(sc->tz_handle), node, *data)); 63078915Smsmith } 631119529Snjl 63278915Smsmith return_VOID; 63378915Smsmith} 63479283Smsmith 63579283Smsmith/* 63679283Smsmith * Sanity-check a temperature value. Assume that setpoints 63779283Smsmith * should be between 0C and 150C. 63879283Smsmith */ 63979283Smsmithstatic void 64079283Smsmithacpi_tz_sanity(struct acpi_tz_softc *sc, int *val, char *what) 64179283Smsmith{ 642119529Snjl if (*val != -1 && (*val < TZ_ZEROC || *val > TZ_ZEROC + 1500)) { 64379283Smsmith device_printf(sc->tz_dev, "%s value is absurd, ignored (%d.%dC)\n", 64479283Smsmith what, TZ_KELVTOC(*val)); 64579283Smsmith *val = -1; 64679283Smsmith } 64779283Smsmith} 64879375Smsmith 64979375Smsmith/* 65079375Smsmith * Respond to a sysctl on the active state node. 65179375Smsmith */ 65279375Smsmithstatic int 65379375Smsmithacpi_tz_active_sysctl(SYSCTL_HANDLER_ARGS) 65479375Smsmith{ 65579375Smsmith struct acpi_tz_softc *sc; 65679375Smsmith int active; 65779375Smsmith int error; 658105282Sjhb ACPI_LOCK_DECL; 65979375Smsmith 66079375Smsmith ACPI_LOCK; 66179375Smsmith 66279375Smsmith sc = (struct acpi_tz_softc *)oidp->oid_arg1; 66379375Smsmith active = sc->tz_active; 66479375Smsmith error = sysctl_handle_int(oidp, &active, 0, req); 66579375Smsmith 666119529Snjl /* Error or no new value */ 667119529Snjl if (error != 0 || req->newptr == NULL) 66879375Smsmith goto out; 669119529Snjl if (active < -1 || active >= TZ_NUMLEVELS) { 67079375Smsmith error = EINVAL; 67179375Smsmith goto out; 67279375Smsmith } 67379375Smsmith 674119529Snjl /* Set new preferred level and re-switch */ 67579375Smsmith sc->tz_requested = active; 67679375Smsmith acpi_tz_monitor(sc); 67779375Smsmith 67879375Smsmith out: 67979375Smsmith ACPI_UNLOCK; 680119529Snjl return (error); 68179375Smsmith} 68279375Smsmith 68378915Smsmith/* 68478915Smsmith * Respond to a Notify event sent to the zone. 68578915Smsmith */ 68678915Smsmithstatic void 68771874Smsmithacpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context) 68871874Smsmith{ 68978915Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)context; 69078915Smsmith 69196926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 69270271Stakawata 69378999Smsmith ACPI_ASSERTLOCK; 69478999Smsmith 69578915Smsmith switch(notify) { 69678915Smsmith case TZ_NOTIFY_TEMPERATURE: 697119529Snjl /* Temperature change occurred */ 698119529Snjl AcpiOsQueueForExecution(OSD_PRIORITY_HIGH, acpi_tz_monitor, sc); 69978915Smsmith break; 70078915Smsmith case TZ_NOTIFY_DEVICES: 70178915Smsmith case TZ_NOTIFY_LEVELS: 702119529Snjl /* Zone devices/setpoints changed */ 703119529Snjl AcpiOsQueueForExecution(OSD_PRIORITY_HIGH, 704119529Snjl (OSD_EXECUTION_CALLBACK)acpi_tz_establish, sc); 70578915Smsmith break; 70678915Smsmith default: 70786552Siwasaki ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 708119529Snjl "unknown Notify event 0x%x\n", notify); 70978915Smsmith break; 71071874Smsmith } 711119529Snjl 712121493Snjl acpi_UserNotify("Thermal", h, notify); 713121493Snjl 71471874Smsmith return_VOID; 71571874Smsmith} 71670271Stakawata 71778915Smsmith/* 71878915Smsmith * Poll the thermal zone. 71978915Smsmith */ 72078915Smsmithstatic void 72191126Smsmithacpi_tz_timeout(struct acpi_tz_softc *sc) 72278915Smsmith{ 723119529Snjl /* Do we need to get the power profile settings? */ 72479375Smsmith if (sc->tz_flags & TZ_FLAG_GETPROFILE) { 72591640Siwasaki acpi_tz_power_profile((void *)sc); 72679375Smsmith sc->tz_flags &= ~TZ_FLAG_GETPROFILE; 72779375Smsmith } 72879375Smsmith 72991126Smsmith ACPI_ASSERTLOCK; 73078915Smsmith 731119529Snjl /* Check the current temperature and take action based on it */ 73291126Smsmith acpi_tz_monitor(sc); 73391126Smsmith 73478915Smsmith /* XXX passive cooling actions? */ 73578915Smsmith} 73679375Smsmith 73779375Smsmith/* 73879375Smsmith * System power profile may have changed; fetch and notify the 73979375Smsmith * thermal zone accordingly. 74079375Smsmith * 74179375Smsmith * Since this can be called from an arbitrary eventhandler, it needs 74279375Smsmith * to get the ACPI lock itself. 74379375Smsmith */ 74479375Smsmithstatic void 74591640Siwasakiacpi_tz_power_profile(void *arg) 74679375Smsmith{ 74779375Smsmith ACPI_STATUS status; 74879375Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg; 74991640Siwasaki int state; 750105282Sjhb ACPI_LOCK_DECL; 75179375Smsmith 75291640Siwasaki state = power_profile_get_state(); 753119529Snjl if (state != POWER_PROFILE_PERFORMANCE && state != POWER_PROFILE_ECONOMY) 754119529Snjl return; 75591640Siwasaki 75679375Smsmith ACPI_LOCK; 75779375Smsmith 75879375Smsmith /* check that we haven't decided there's no _SCP method */ 759119529Snjl if ((sc->tz_flags & TZ_FLAG_NO_SCP) == 0) { 76079375Smsmith 761119529Snjl /* Call _SCP to set the new profile */ 762126560Snjl status = acpi_SetInteger(sc->tz_handle, "_SCP", 763126560Snjl (state == POWER_PROFILE_PERFORMANCE) ? 0 : 1); 764119529Snjl if (ACPI_FAILURE(status)) { 76579385Smsmith if (status != AE_NOT_FOUND) 766119529Snjl ACPI_VPRINT(sc->tz_dev, 767119529Snjl acpi_device_get_parent_softc(sc->tz_dev), 768119529Snjl "can't evaluate %s._SCP - %s\n", 769119529Snjl acpi_name(sc->tz_handle), 770119529Snjl AcpiFormatException(status)); 77179375Smsmith sc->tz_flags |= TZ_FLAG_NO_SCP; 77279375Smsmith } else { 773119529Snjl /* We have to re-evaluate the entire zone now */ 774119529Snjl AcpiOsQueueForExecution(OSD_PRIORITY_HIGH, 775119529Snjl (OSD_EXECUTION_CALLBACK)acpi_tz_establish, 776119529Snjl sc); 77779375Smsmith } 77879375Smsmith } 779119529Snjl 78079375Smsmith ACPI_UNLOCK; 78179375Smsmith} 78279375Smsmith 78391126Smsmith/* 78491126Smsmith * Thermal zone monitor thread. 78591126Smsmith */ 78691126Smsmithstatic void 78791126Smsmithacpi_tz_thread(void *arg) 78891126Smsmith{ 78991126Smsmith device_t *devs; 79091126Smsmith int devcount, i; 791105282Sjhb ACPI_LOCK_DECL; 79291126Smsmith 79396926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 79491126Smsmith 79591126Smsmith devs = NULL; 79691126Smsmith devcount = 0; 79791126Smsmith 79891126Smsmith for (;;) { 799119529Snjl tsleep(&acpi_tz_proc, PZERO, "tzpoll", hz * acpi_tz_polling_rate); 80091126Smsmith 801105282Sjhb#if __FreeBSD_version >= 500000 80291215Smsmith mtx_lock(&Giant); 803105282Sjhb#endif 80491215Smsmith 80591126Smsmith if (devcount == 0) 80691126Smsmith devclass_get_devices(acpi_tz_devclass, &devs, &devcount); 80791126Smsmith 80891126Smsmith ACPI_LOCK; 80991126Smsmith for (i = 0; i < devcount; i++) 81091126Smsmith acpi_tz_timeout(device_get_softc(devs[i])); 81191126Smsmith ACPI_UNLOCK; 81291215Smsmith 813105282Sjhb#if __FreeBSD_version >= 500000 81491215Smsmith mtx_unlock(&Giant); 815105282Sjhb#endif 81691126Smsmith } 81791126Smsmith} 818