acpi_thermal.c revision 121493
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 121493 2003-10-25 05:03:25Z 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 5278915Smsmith#define TZ_NOTIFY_TEMPERATURE 0x80 5378915Smsmith#define TZ_NOTIFY_DEVICES 0x81 5478915Smsmith#define TZ_NOTIFY_LEVELS 0x82 5578915Smsmith 56119529Snjl/* Check for temperature changes every 30 seconds by default */ 57119529Snjl#define TZ_POLLRATE 30 5878915Smsmith 59119529Snjl/* ACPI spec defines this */ 60119529Snjl#define TZ_NUMLEVELS 10 6179375Smsmithstruct acpi_tz_zone { 6278915Smsmith int ac[TZ_NUMLEVELS]; 6378915Smsmith ACPI_BUFFER al[TZ_NUMLEVELS]; 6478915Smsmith int crt; 6578915Smsmith int hot; 6678915Smsmith ACPI_BUFFER psl; 6778915Smsmith int psv; 6878915Smsmith int tc1; 6978915Smsmith int tc2; 7078915Smsmith int tsp; 7178915Smsmith int tzp; 7278915Smsmith}; 7378915Smsmith 7478915Smsmith 7567761Smsmithstruct acpi_tz_softc { 76119529Snjl device_t tz_dev; 77119529Snjl ACPI_HANDLE tz_handle; /*Thermal zone handle*/ 78119529Snjl int tz_temperature; /*Current temperature*/ 79119529Snjl int tz_active; /*Current active cooling*/ 8079375Smsmith#define TZ_ACTIVE_NONE -1 81119529Snjl int tz_requested; /*Minimum active cooling*/ 82119529Snjl int tz_thflags; /*Current temp-related flags*/ 8379375Smsmith#define TZ_THFLAG_NONE 0 8479375Smsmith#define TZ_THFLAG_PSV (1<<0) 8579375Smsmith#define TZ_THFLAG_HOT (1<<2) 8679375Smsmith#define TZ_THFLAG_CRT (1<<3) 8779283Smsmith int tz_flags; 88119529Snjl#define TZ_FLAG_NO_SCP (1<<0) /*No _SCP method*/ 89119529Snjl#define TZ_FLAG_GETPROFILE (1<<1) /*Get power_profile in timeout*/ 90119529Snjl struct timespec tz_cooling_started; 91119529Snjl /*Current cooling starting time*/ 9279283Smsmith 93119529Snjl struct sysctl_ctx_list tz_sysctl_ctx; 9479283Smsmith struct sysctl_oid *tz_sysctl_tree; 9578915Smsmith 96119529Snjl struct acpi_tz_zone tz_zone; /*Thermal zone parameters*/ 9788420Siwasaki int tz_tmp_updating; 9867761Smsmith}; 9967761Smsmith 10067761Smsmithstatic int acpi_tz_probe(device_t dev); 10167761Smsmithstatic int acpi_tz_attach(device_t dev); 10278915Smsmithstatic int acpi_tz_establish(struct acpi_tz_softc *sc); 103119529Snjlstatic void acpi_tz_monitor(void *Context); 10478915Smsmithstatic void acpi_tz_all_off(struct acpi_tz_softc *sc); 10578915Smsmithstatic void acpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg); 10678915Smsmithstatic void acpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg); 107119529Snjlstatic void acpi_tz_getparam(struct acpi_tz_softc *sc, char *node, 108119529Snjl int *data); 10979283Smsmithstatic void acpi_tz_sanity(struct acpi_tz_softc *sc, int *val, char *what); 11079375Smsmithstatic int acpi_tz_active_sysctl(SYSCTL_HANDLER_ARGS); 111119529Snjlstatic void acpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, 112119529Snjl void *context); 11391126Smsmithstatic void acpi_tz_timeout(struct acpi_tz_softc *sc); 11491640Siwasakistatic void acpi_tz_power_profile(void *arg); 11591126Smsmithstatic void acpi_tz_thread(void *arg); 11691126Smsmith 11767761Smsmithstatic device_method_t acpi_tz_methods[] = { 11867761Smsmith /* Device interface */ 11967761Smsmith DEVMETHOD(device_probe, acpi_tz_probe), 12067761Smsmith DEVMETHOD(device_attach, acpi_tz_attach), 12167761Smsmith 12267761Smsmith {0, 0} 12367761Smsmith}; 12467761Smsmith 12567761Smsmithstatic driver_t acpi_tz_driver = { 12667761Smsmith "acpi_tz", 12767761Smsmith acpi_tz_methods, 12867761Smsmith sizeof(struct acpi_tz_softc), 12967761Smsmith}; 13067761Smsmith 13189054Smsmithstatic devclass_t acpi_tz_devclass; 13267761SmsmithDRIVER_MODULE(acpi_tz, acpi, acpi_tz_driver, acpi_tz_devclass, 0, 0); 13367761Smsmith 13479283Smsmithstatic struct sysctl_ctx_list acpi_tz_sysctl_ctx; 13579283Smsmithstatic struct sysctl_oid *acpi_tz_sysctl_tree; 13679283Smsmith 137119529Snjl/* Minimum cooling run time */ 138119529Snjlstatic int acpi_tz_min_runtime = 0; 13988420Siwasakistatic int acpi_tz_polling_rate = TZ_POLLRATE; 14085699Siwasaki 141119529Snjl/* Timezone polling thread */ 142119529Snjlstatic struct proc *acpi_tz_proc; 143119529Snjl 14478915Smsmith/* 14578915Smsmith * Match an ACPI thermal zone. 14678915Smsmith */ 14767761Smsmithstatic int 14867761Smsmithacpi_tz_probe(device_t dev) 14967761Smsmith{ 15078999Smsmith int result; 151105282Sjhb ACPI_LOCK_DECL; 15278999Smsmith 15378999Smsmith ACPI_LOCK; 15478999Smsmith 155119529Snjl /* No FUNCTION_TRACE - too noisy */ 15669744Smsmith 157119529Snjl if (acpi_get_type(dev) == ACPI_TYPE_THERMAL && !acpi_disabled("thermal")) { 158120453Snjl device_set_desc(dev, "Thermal Zone"); 15978999Smsmith result = -10; 16078999Smsmith } else { 16178999Smsmith result = ENXIO; 16267761Smsmith } 16378999Smsmith ACPI_UNLOCK; 164119529Snjl return (result); 16567761Smsmith} 16667761Smsmith 16778915Smsmith/* 16878915Smsmith * Attach to an ACPI thermal zone. 16978915Smsmith */ 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]; 177105282Sjhb ACPI_LOCK_DECL; 17867761Smsmith 17996926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 18069744Smsmith 18178999Smsmith ACPI_LOCK; 18278999Smsmith 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; 18788420Siwasaki sc->tz_tmp_updating = 0; 18867761Smsmith 18978915Smsmith /* 19078915Smsmith * Parse the current state of the thermal zone and build control 19178915Smsmith * structures. 19278915Smsmith */ 19378915Smsmith if ((error = acpi_tz_establish(sc)) != 0) 19478999Smsmith goto out; 19578915Smsmith 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, ""); 22879283Smsmith SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 22979283Smsmith OID_AUTO, "temperature", CTLFLAG_RD, 23079283Smsmith &sc->tz_temperature, 0, "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, ""); 24179283Smsmith SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 24279283Smsmith OID_AUTO, "_HOT", CTLFLAG_RD, 24379375Smsmith &sc->tz_zone.hot, 0, ""); 24479283Smsmith SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 24579283Smsmith OID_AUTO, "_CRT", CTLFLAG_RD, 24679375Smsmith &sc->tz_zone.crt, 0, ""); 24786399Siwasaki SYSCTL_ADD_OPAQUE(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 24886399Siwasaki OID_AUTO, "_ACx", CTLFLAG_RD, &sc->tz_zone.ac, 24986399Siwasaki sizeof(sc->tz_zone.ac), "I", ""); 25079283Smsmith 25179283Smsmith /* 25279375Smsmith * Register our power profile event handler, and flag it for a manual 25379375Smsmith * invocation by our timeout. We defer it like this so that the rest 25479375Smsmith * of the subsystem has time to come up. 25579375Smsmith */ 25691640Siwasaki EVENTHANDLER_REGISTER(power_profile_change, acpi_tz_power_profile, sc, 0); 25779375Smsmith sc->tz_flags |= TZ_FLAG_GETPROFILE; 25879375Smsmith 25979375Smsmith /* 26071874Smsmith * Don't bother evaluating/printing the temperature at this point; 26171874Smsmith * on many systems it'll be bogus until the EC is running. 26271874Smsmith */ 26378999Smsmith 26491126Smsmith /* 26591126Smsmith * Create our thread; we only need one, it will service all of the 26691126Smsmith * thermal zones. 26791126Smsmith */ 26891126Smsmith if (acpi_tz_proc == NULL) { 26991126Smsmith error = kthread_create(acpi_tz_thread, NULL, &acpi_tz_proc, 270104354Sscottl RFHIGHPID, 0, "acpi_thermal"); 27191126Smsmith if (error != 0) { 272119529Snjl device_printf(sc->tz_dev, "could not create thread - %d", 273119529Snjl error); 27491126Smsmith goto out; 27591126Smsmith } 27691126Smsmith } 27791126Smsmith 27878999Smsmith out: 27978999Smsmith ACPI_UNLOCK; 28079375Smsmith 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 29878999Smsmith ACPI_ASSERTLOCK; 29978999Smsmith 300119529Snjl /* Power everything off and erase any existing state. */ 30178915Smsmith acpi_tz_all_off(sc); 30278915Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) 30379375Smsmith if (sc->tz_zone.al[i].Pointer != NULL) 30479375Smsmith AcpiOsFree(sc->tz_zone.al[i].Pointer); 30579375Smsmith if (sc->tz_zone.psl.Pointer != NULL) 30679375Smsmith AcpiOsFree(sc->tz_zone.psl.Pointer); 30779375Smsmith bzero(&sc->tz_zone, sizeof(sc->tz_zone)); 30878915Smsmith 309119529Snjl /* Evaluate thermal zone parameters. */ 31078915Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) { 31178915Smsmith sprintf(nbuf, "_AC%d", i); 31279375Smsmith acpi_tz_getparam(sc, nbuf, &sc->tz_zone.ac[i]); 31378915Smsmith sprintf(nbuf, "_AL%d", i); 31491126Smsmith sc->tz_zone.al[i].Length = ACPI_ALLOCATE_BUFFER; 31591126Smsmith sc->tz_zone.al[i].Pointer = NULL; 31691126Smsmith AcpiEvaluateObject(sc->tz_handle, nbuf, NULL, &sc->tz_zone.al[i]); 31779375Smsmith obj = (ACPI_OBJECT *)sc->tz_zone.al[i].Pointer; 31878915Smsmith if (obj != NULL) { 319119529Snjl /* Should be a package containing a list of power objects */ 32078915Smsmith if (obj->Type != ACPI_TYPE_PACKAGE) { 321119529Snjl device_printf(sc->tz_dev, "%s has unknown type %d, rejecting\n", 32278915Smsmith nbuf, obj->Type); 323119529Snjl return_VALUE (ENXIO); 32478915Smsmith } 32578915Smsmith } 32678915Smsmith } 32779375Smsmith acpi_tz_getparam(sc, "_CRT", &sc->tz_zone.crt); 32879375Smsmith acpi_tz_getparam(sc, "_HOT", &sc->tz_zone.hot); 32991126Smsmith sc->tz_zone.psl.Length = ACPI_ALLOCATE_BUFFER; 33091126Smsmith sc->tz_zone.psl.Pointer = NULL; 33191126Smsmith AcpiEvaluateObject(sc->tz_handle, "_PSL", NULL, &sc->tz_zone.psl); 33279375Smsmith acpi_tz_getparam(sc, "_PSV", &sc->tz_zone.psv); 33379375Smsmith acpi_tz_getparam(sc, "_TC1", &sc->tz_zone.tc1); 33479375Smsmith acpi_tz_getparam(sc, "_TC2", &sc->tz_zone.tc2); 33579375Smsmith acpi_tz_getparam(sc, "_TSP", &sc->tz_zone.tsp); 33679375Smsmith acpi_tz_getparam(sc, "_TZP", &sc->tz_zone.tzp); 33778915Smsmith 33878915Smsmith /* 33979283Smsmith * Sanity-check the values we've been given. 34079283Smsmith * 34179283Smsmith * XXX what do we do about systems that give us the same value for 34279283Smsmith * more than one of these setpoints? 34379283Smsmith */ 34479375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.crt, "_CRT"); 34579375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.hot, "_HOT"); 34679375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.psv, "_PSV"); 34779283Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) 34879375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.ac[i], "_ACx"); 34979283Smsmith 35079283Smsmith /* 35178915Smsmith * Power off everything that we've just been given. 35278915Smsmith */ 35378915Smsmith acpi_tz_all_off(sc); 35478915Smsmith 355119529Snjl return_VALUE (0); 35678915Smsmith} 35778915Smsmith 35885699Siwasakistatic char *aclevel_string[] = { 35985699Siwasaki "NONE", "_AC0", "_AC1", "_AC2", "_AC3", "_AC4", 36085699Siwasaki "_AC5", "_AC6", "_AC7", "_AC8", "_AC9" }; 36185699Siwasaki 36285699Siwasakistatic __inline const char * 36385699Siwasakiacpi_tz_aclevel_string(int active) 36485699Siwasaki{ 365119529Snjl if (active < -1 || active >= TZ_NUMLEVELS) 36685699Siwasaki return (aclevel_string[0]); 36785699Siwasaki 36885699Siwasaki return (aclevel_string[active+1]); 36985699Siwasaki} 37085699Siwasaki 37178915Smsmith/* 37278915Smsmith * Evaluate the condition of a thermal zone, take appropriate actions. 37378915Smsmith */ 37471874Smsmithstatic void 375119529Snjlacpi_tz_monitor(void *Context) 37671874Smsmith{ 377119529Snjl struct acpi_tz_softc *sc; 378119529Snjl struct timespec curtime; 37979283Smsmith int temp; 38078915Smsmith int i; 38179283Smsmith int newactive, newflags; 38286399Siwasaki ACPI_STATUS status; 38370271Stakawata 38496926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 38570271Stakawata 38678999Smsmith ACPI_ASSERTLOCK; 38778999Smsmith 388119529Snjl sc = (struct acpi_tz_softc *)Context; 389119529Snjl if (sc->tz_tmp_updating) 39088420Siwasaki goto out; 39188420Siwasaki sc->tz_tmp_updating = 1; 39288420Siwasaki 393119529Snjl /* Get the current temperature. */ 394119529Snjl status = acpi_EvaluateInteger(sc->tz_handle, "_TMP", &temp); 395119529Snjl if (ACPI_FAILURE(status)) { 39686552Siwasaki ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 39786552Siwasaki "error fetching current temperature -- %s\n", 39886552Siwasaki AcpiFormatException(status)); 39978915Smsmith /* XXX disable zone? go to max cooling? */ 40088420Siwasaki goto out; 40171874Smsmith } 40288420Siwasaki 40382372Smsmith ACPI_DEBUG_PRINT((ACPI_DB_VALUES, "got %d.%dC\n", TZ_KELVTOC(temp))); 40479283Smsmith sc->tz_temperature = temp; 40578915Smsmith 40678915Smsmith /* 40778915Smsmith * Work out what we ought to be doing right now. 40879283Smsmith * 40979283Smsmith * Note that the _ACx levels sort from hot to cold. 41078915Smsmith */ 41179283Smsmith newactive = TZ_ACTIVE_NONE; 41279375Smsmith for (i = TZ_NUMLEVELS - 1; i >= 0; i--) { 41379375Smsmith if ((sc->tz_zone.ac[i] != -1) && (temp >= sc->tz_zone.ac[i])) { 41479283Smsmith newactive = i; 41582967Siwasaki if (sc->tz_active != newactive) { 416119529Snjl ACPI_VPRINT(sc->tz_dev, 417119529Snjl acpi_device_get_parent_softc(sc->tz_dev), 418119529Snjl "_AC%d: temperature %d.%d >= setpoint %d.%d\n", i, 419119529Snjl TZ_KELVTOC(temp), TZ_KELVTOC(sc->tz_zone.ac[i])); 42085699Siwasaki getnanotime(&sc->tz_cooling_started); 42182967Siwasaki } 42279375Smsmith } 42379375Smsmith } 42479283Smsmith 42585699Siwasaki /* 42685699Siwasaki * We are going to get _ACx level down (colder side), but give a guaranteed 42785699Siwasaki * minimum cooling run time if requested. 42885699Siwasaki */ 42985699Siwasaki if (acpi_tz_min_runtime > 0 && sc->tz_active != TZ_ACTIVE_NONE && 43085699Siwasaki (newactive == TZ_ACTIVE_NONE || newactive > sc->tz_active)) { 431119529Snjl 43285699Siwasaki getnanotime(&curtime); 43385699Siwasaki timespecsub(&curtime, &sc->tz_cooling_started); 434119529Snjl if (curtime.tv_sec < acpi_tz_min_runtime) 43585699Siwasaki newactive = sc->tz_active; 43685699Siwasaki } 43785699Siwasaki 438119529Snjl /* Handle user override of active mode */ 43979375Smsmith if (sc->tz_requested > newactive) 44079375Smsmith newactive = sc->tz_requested; 44178915Smsmith 44279375Smsmith /* update temperature-related flags */ 44379375Smsmith newflags = TZ_THFLAG_NONE; 44479375Smsmith if ((sc->tz_zone.psv != -1) && (temp >= sc->tz_zone.psv)) 44579375Smsmith newflags |= TZ_THFLAG_PSV; 44679375Smsmith if ((sc->tz_zone.hot != -1) && (temp >= sc->tz_zone.hot)) 44779375Smsmith newflags |= TZ_THFLAG_HOT; 44879375Smsmith if ((sc->tz_zone.crt != -1) && (temp >= sc->tz_zone.crt)) 44979375Smsmith newflags |= TZ_THFLAG_CRT; 45079375Smsmith 451119529Snjl /* If the active cooling state has changed, we have to switch things. */ 45279283Smsmith if (newactive != sc->tz_active) { 453119529Snjl /* Turn off the cooling devices that are on, if any are */ 45479283Smsmith if (sc->tz_active != TZ_ACTIVE_NONE) 455119529Snjl acpi_ForeachPackageObject( 456119529Snjl (ACPI_OBJECT *)sc->tz_zone.al[sc->tz_active].Pointer, 457119529Snjl acpi_tz_switch_cooler_off, sc); 45878915Smsmith 459119529Snjl /* Turn on cooling devices that are required, if any are */ 460119529Snjl if (newactive != TZ_ACTIVE_NONE) { 461119529Snjl acpi_ForeachPackageObject( 462119529Snjl (ACPI_OBJECT *)sc->tz_zone.al[newactive].Pointer, 463119529Snjl acpi_tz_switch_cooler_on, sc); 464119529Snjl } 46586552Siwasaki ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 466119529Snjl "switched from %s to %s: %d.%dC\n", 467119529Snjl acpi_tz_aclevel_string(sc->tz_active), 468119529Snjl acpi_tz_aclevel_string(newactive), TZ_KELVTOC(temp)); 46979283Smsmith sc->tz_active = newactive; 47079283Smsmith } 47178915Smsmith 472119529Snjl /* XXX (de)activate any passive cooling that may be required. */ 47378915Smsmith 47478915Smsmith /* 47579283Smsmith * If we have just become _HOT or _CRT, warn the user. 47679283Smsmith * 47779283Smsmith * We should actually shut down at this point, but it's not clear 47879283Smsmith * that some systems don't actually map _CRT to the same value as _AC0. 47978915Smsmith */ 480119529Snjl if ((newflags & (TZ_THFLAG_HOT | TZ_THFLAG_CRT)) != 0 && 481119529Snjl (sc->tz_thflags & (TZ_THFLAG_HOT | TZ_THFLAG_CRT)) == 0) { 482119529Snjl 483119529Snjl device_printf(sc->tz_dev, 484119529Snjl "WARNING - current temperature (%d.%dC) exceeds system limits\n", 48597274Sbde TZ_KELVTOC(sc->tz_temperature)); 48679283Smsmith /* shutdown_nice(RB_POWEROFF);*/ 48778915Smsmith } 48879375Smsmith sc->tz_thflags = newflags; 48978915Smsmith 49088420Siwasakiout: 49188420Siwasaki sc->tz_tmp_updating = 0; 49271874Smsmith return_VOID; 49371874Smsmith} 49470271Stakawata 49578915Smsmith/* 49678915Smsmith * Turn off all the cooling devices. 49778915Smsmith */ 49871874Smsmithstatic void 49978915Smsmithacpi_tz_all_off(struct acpi_tz_softc *sc) 50078915Smsmith{ 50178915Smsmith int i; 50278915Smsmith 50396926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 50478999Smsmith 50578999Smsmith ACPI_ASSERTLOCK; 50678915Smsmith 507119529Snjl /* Scan all the _ALx objects and turn them all off. */ 50878915Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) { 50979375Smsmith if (sc->tz_zone.al[i].Pointer == NULL) 51078915Smsmith continue; 51179375Smsmith acpi_ForeachPackageObject((ACPI_OBJECT *)sc->tz_zone.al[i].Pointer, 51278915Smsmith acpi_tz_switch_cooler_off, sc); 51378915Smsmith } 51478915Smsmith 51578915Smsmith /* 51678915Smsmith * XXX revert any passive-cooling options. 51778915Smsmith */ 51878915Smsmith 51979283Smsmith sc->tz_active = TZ_ACTIVE_NONE; 52079375Smsmith sc->tz_thflags = TZ_THFLAG_NONE; 521119529Snjl 52278915Smsmith return_VOID; 52378915Smsmith} 52478915Smsmith 52578915Smsmith/* 52678915Smsmith * Given an object, verify that it's a reference to a device of some sort, 52778915Smsmith * and try to switch it off. 52878915Smsmith */ 52978915Smsmithstatic void 53078915Smsmithacpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg) 53178915Smsmith{ 53279375Smsmith ACPI_HANDLE cooler; 53378915Smsmith 53496926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 53578915Smsmith 53678999Smsmith ACPI_ASSERTLOCK; 53778999Smsmith 53878915Smsmith switch(obj->Type) { 539102470Siwasaki case ACPI_TYPE_ANY: 540119529Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s off\n", 541119529Snjl acpi_name(obj->Reference.Handle))); 542102470Siwasaki 543102470Siwasaki acpi_pwr_switch_consumer(obj->Reference.Handle, ACPI_STATE_D3); 544102470Siwasaki break; 54578915Smsmith case ACPI_TYPE_STRING: 546119529Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s off\n", 547119529Snjl obj->String.Pointer)); 54878915Smsmith 54978915Smsmith /* 55078915Smsmith * Find the handle for the device and turn it off. 55178915Smsmith * The String object here seems to contain a fully-qualified path, so we 55278915Smsmith * don't have to search for it in our parents. 55378915Smsmith * 55478915Smsmith * XXX This may not always be the case. 55578915Smsmith */ 55691126Smsmith if (ACPI_SUCCESS(AcpiGetHandle(NULL, obj->String.Pointer, &cooler))) 55778915Smsmith acpi_pwr_switch_consumer(cooler, ACPI_STATE_D3); 55878915Smsmith break; 55978915Smsmith default: 560119529Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, 561119529Snjl "called to handle unsupported object type %d\n", 562119529Snjl obj->Type)); 56378915Smsmith break; 56478915Smsmith } 565119529Snjl 56679375Smsmith return_VOID; 56778915Smsmith} 56878915Smsmith 56978915Smsmith/* 57078915Smsmith * Given an object, verify that it's a reference to a device of some sort, 57178915Smsmith * and try to switch it on. 57278915Smsmith * 57378915Smsmith * XXX replication of off/on function code is bad, mmmkay? 57478915Smsmith */ 57578915Smsmithstatic void 57678915Smsmithacpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg) 57778915Smsmith{ 57878915Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg; 57978999Smsmith ACPI_HANDLE cooler; 58079375Smsmith ACPI_STATUS status; 58179375Smsmith 58296926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 58378915Smsmith 58478999Smsmith ACPI_ASSERTLOCK; 58578999Smsmith 58678915Smsmith switch(obj->Type) { 587102470Siwasaki case ACPI_TYPE_ANY: 588119529Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s on\n", 589119529Snjl acpi_name(obj->Reference.Handle))); 590102470Siwasaki 591119529Snjl status = acpi_pwr_switch_consumer(obj->Reference.Handle, ACPI_STATE_D0); 592119529Snjl if (ACPI_FAILURE(status)) { 593102470Siwasaki ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 594119529Snjl "failed to activate %s - %s\n", 595119529Snjl acpi_name(obj->Reference.Handle), 596119529Snjl AcpiFormatException(status)); 597102470Siwasaki } 598102470Siwasaki break; 59978915Smsmith case ACPI_TYPE_STRING: 600119529Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s on\n", 601119529Snjl obj->String.Pointer)); 60278915Smsmith 60378999Smsmith /* 60478999Smsmith * Find the handle for the device and turn it off. 60578999Smsmith * The String object here seems to contain a fully-qualified path, so we 60678999Smsmith * don't have to search for it in our parents. 60778999Smsmith * 60878999Smsmith * XXX This may not always be the case. 60978999Smsmith */ 61091126Smsmith if (ACPI_SUCCESS(AcpiGetHandle(NULL, obj->String.Pointer, &cooler))) { 611119529Snjl status = acpi_pwr_switch_consumer(cooler, ACPI_STATE_D0); 612119529Snjl if (ACPI_FAILURE(status)) { 613119529Snjl ACPI_VPRINT(sc->tz_dev, 614119529Snjl acpi_device_get_parent_softc(sc->tz_dev), 615119529Snjl "failed to activate %s - %s\n", 616119529Snjl obj->String.Pointer, AcpiFormatException(status)); 61779375Smsmith } 61879375Smsmith } else { 61986552Siwasaki ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 620119529Snjl "couldn't find %s\n", obj->String.Pointer); 62179375Smsmith } 62278915Smsmith break; 62378915Smsmith default: 624119529Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "unsupported object type %d\n", 62582372Smsmith obj->Type)); 62678915Smsmith break; 62778915Smsmith } 628119529Snjl 629119529Snjl return_VOID; 63078915Smsmith} 63178915Smsmith 63278915Smsmith/* 63378915Smsmith * Read/debug-print a parameter, default it to -1. 63478915Smsmith */ 63578915Smsmithstatic void 63678915Smsmithacpi_tz_getparam(struct acpi_tz_softc *sc, char *node, int *data) 63778915Smsmith{ 63878915Smsmith 63996926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 64078915Smsmith 64178999Smsmith ACPI_ASSERTLOCK; 64278999Smsmith 64391126Smsmith if (ACPI_FAILURE(acpi_EvaluateInteger(sc->tz_handle, node, data))) { 64478915Smsmith *data = -1; 64578915Smsmith } else { 646119529Snjl ACPI_DEBUG_PRINT((ACPI_DB_VALUES, "%s.%s = %d\n", 647119529Snjl acpi_name(sc->tz_handle), node, *data)); 64878915Smsmith } 649119529Snjl 65078915Smsmith return_VOID; 65178915Smsmith} 65279283Smsmith 65379283Smsmith/* 65479283Smsmith * Sanity-check a temperature value. Assume that setpoints 65579283Smsmith * should be between 0C and 150C. 65679283Smsmith */ 65779283Smsmithstatic void 65879283Smsmithacpi_tz_sanity(struct acpi_tz_softc *sc, int *val, char *what) 65979283Smsmith{ 660119529Snjl if (*val != -1 && (*val < TZ_ZEROC || *val > TZ_ZEROC + 1500)) { 66179283Smsmith device_printf(sc->tz_dev, "%s value is absurd, ignored (%d.%dC)\n", 66279283Smsmith what, TZ_KELVTOC(*val)); 66379283Smsmith *val = -1; 66479283Smsmith } 66579283Smsmith} 66679375Smsmith 66779375Smsmith/* 66879375Smsmith * Respond to a sysctl on the active state node. 66979375Smsmith */ 67079375Smsmithstatic int 67179375Smsmithacpi_tz_active_sysctl(SYSCTL_HANDLER_ARGS) 67279375Smsmith{ 67379375Smsmith struct acpi_tz_softc *sc; 67479375Smsmith int active; 67579375Smsmith int error; 676105282Sjhb ACPI_LOCK_DECL; 67779375Smsmith 67879375Smsmith ACPI_LOCK; 67979375Smsmith 68079375Smsmith sc = (struct acpi_tz_softc *)oidp->oid_arg1; 68179375Smsmith active = sc->tz_active; 68279375Smsmith error = sysctl_handle_int(oidp, &active, 0, req); 68379375Smsmith 684119529Snjl /* Error or no new value */ 685119529Snjl if (error != 0 || req->newptr == NULL) 68679375Smsmith goto out; 687119529Snjl if (active < -1 || active >= TZ_NUMLEVELS) { 68879375Smsmith error = EINVAL; 68979375Smsmith goto out; 69079375Smsmith } 69179375Smsmith 692119529Snjl /* Set new preferred level and re-switch */ 69379375Smsmith sc->tz_requested = active; 69479375Smsmith acpi_tz_monitor(sc); 69579375Smsmith 69679375Smsmith out: 69779375Smsmith ACPI_UNLOCK; 698119529Snjl return (error); 69979375Smsmith} 70079375Smsmith 70178915Smsmith/* 70278915Smsmith * Respond to a Notify event sent to the zone. 70378915Smsmith */ 70478915Smsmithstatic void 70571874Smsmithacpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context) 70671874Smsmith{ 70778915Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)context; 70878915Smsmith 70996926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 71070271Stakawata 71178999Smsmith ACPI_ASSERTLOCK; 71278999Smsmith 71378915Smsmith switch(notify) { 71478915Smsmith case TZ_NOTIFY_TEMPERATURE: 715119529Snjl /* Temperature change occurred */ 716119529Snjl AcpiOsQueueForExecution(OSD_PRIORITY_HIGH, acpi_tz_monitor, sc); 71778915Smsmith break; 71878915Smsmith case TZ_NOTIFY_DEVICES: 71978915Smsmith case TZ_NOTIFY_LEVELS: 720119529Snjl /* Zone devices/setpoints changed */ 721119529Snjl AcpiOsQueueForExecution(OSD_PRIORITY_HIGH, 722119529Snjl (OSD_EXECUTION_CALLBACK)acpi_tz_establish, sc); 72378915Smsmith break; 72478915Smsmith default: 72586552Siwasaki ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 726119529Snjl "unknown Notify event 0x%x\n", notify); 72778915Smsmith break; 72871874Smsmith } 729119529Snjl 730121493Snjl acpi_UserNotify("Thermal", h, notify); 731121493Snjl 73271874Smsmith return_VOID; 73371874Smsmith} 73470271Stakawata 73578915Smsmith/* 73678915Smsmith * Poll the thermal zone. 73778915Smsmith */ 73878915Smsmithstatic void 73991126Smsmithacpi_tz_timeout(struct acpi_tz_softc *sc) 74078915Smsmith{ 741119529Snjl /* Do we need to get the power profile settings? */ 74279375Smsmith if (sc->tz_flags & TZ_FLAG_GETPROFILE) { 74391640Siwasaki acpi_tz_power_profile((void *)sc); 74479375Smsmith sc->tz_flags &= ~TZ_FLAG_GETPROFILE; 74579375Smsmith } 74679375Smsmith 74791126Smsmith ACPI_ASSERTLOCK; 74878915Smsmith 749119529Snjl /* Check the current temperature and take action based on it */ 75091126Smsmith acpi_tz_monitor(sc); 75191126Smsmith 75278915Smsmith /* XXX passive cooling actions? */ 75378915Smsmith} 75479375Smsmith 75579375Smsmith/* 75679375Smsmith * System power profile may have changed; fetch and notify the 75779375Smsmith * thermal zone accordingly. 75879375Smsmith * 75979375Smsmith * Since this can be called from an arbitrary eventhandler, it needs 76079375Smsmith * to get the ACPI lock itself. 76179375Smsmith */ 76279375Smsmithstatic void 76391640Siwasakiacpi_tz_power_profile(void *arg) 76479375Smsmith{ 76579375Smsmith ACPI_OBJECT_LIST args; 76679375Smsmith ACPI_OBJECT obj; 76779375Smsmith ACPI_STATUS status; 76879375Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg; 76991640Siwasaki int state; 770105282Sjhb ACPI_LOCK_DECL; 77179375Smsmith 77291640Siwasaki state = power_profile_get_state(); 773119529Snjl if (state != POWER_PROFILE_PERFORMANCE && state != POWER_PROFILE_ECONOMY) 774119529Snjl return; 77591640Siwasaki 77679375Smsmith ACPI_LOCK; 77779375Smsmith 77879375Smsmith /* check that we haven't decided there's no _SCP method */ 779119529Snjl if ((sc->tz_flags & TZ_FLAG_NO_SCP) == 0) { 78079375Smsmith 781119529Snjl /* Call _SCP to set the new profile */ 78279375Smsmith obj.Type = ACPI_TYPE_INTEGER; 78391640Siwasaki obj.Integer.Value = (state == POWER_PROFILE_PERFORMANCE) ? 0 : 1; 78479375Smsmith args.Count = 1; 78579375Smsmith args.Pointer = &obj; 786119529Snjl status = AcpiEvaluateObject(sc->tz_handle, "_SCP", &args, NULL); 787119529Snjl if (ACPI_FAILURE(status)) { 78879385Smsmith if (status != AE_NOT_FOUND) 789119529Snjl ACPI_VPRINT(sc->tz_dev, 790119529Snjl acpi_device_get_parent_softc(sc->tz_dev), 791119529Snjl "can't evaluate %s._SCP - %s\n", 792119529Snjl acpi_name(sc->tz_handle), 793119529Snjl AcpiFormatException(status)); 79479375Smsmith sc->tz_flags |= TZ_FLAG_NO_SCP; 79579375Smsmith } else { 796119529Snjl /* We have to re-evaluate the entire zone now */ 797119529Snjl AcpiOsQueueForExecution(OSD_PRIORITY_HIGH, 798119529Snjl (OSD_EXECUTION_CALLBACK)acpi_tz_establish, 799119529Snjl sc); 80079375Smsmith } 80179375Smsmith } 802119529Snjl 80379375Smsmith ACPI_UNLOCK; 80479375Smsmith} 80579375Smsmith 80691126Smsmith/* 80791126Smsmith * Thermal zone monitor thread. 80891126Smsmith */ 80991126Smsmithstatic void 81091126Smsmithacpi_tz_thread(void *arg) 81191126Smsmith{ 81291126Smsmith device_t *devs; 81391126Smsmith int devcount, i; 814105282Sjhb ACPI_LOCK_DECL; 81591126Smsmith 81696926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 81791126Smsmith 81891126Smsmith devs = NULL; 81991126Smsmith devcount = 0; 82091126Smsmith 82191126Smsmith for (;;) { 822119529Snjl tsleep(&acpi_tz_proc, PZERO, "tzpoll", hz * acpi_tz_polling_rate); 82391126Smsmith 824105282Sjhb#if __FreeBSD_version >= 500000 82591215Smsmith mtx_lock(&Giant); 826105282Sjhb#endif 82791215Smsmith 82891126Smsmith if (devcount == 0) 82991126Smsmith devclass_get_devices(acpi_tz_devclass, &devs, &devcount); 83091126Smsmith 83191126Smsmith ACPI_LOCK; 83291126Smsmith for (i = 0; i < devcount; i++) 83391126Smsmith acpi_tz_timeout(device_get_softc(devs[i])); 83491126Smsmith ACPI_UNLOCK; 83591215Smsmith 836105282Sjhb#if __FreeBSD_version >= 500000 83791215Smsmith mtx_unlock(&Giant); 838105282Sjhb#endif 83991126Smsmith } 84091126Smsmith} 841