acpi_thermal.c revision 91215
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 * $FreeBSD: head/sys/dev/acpica/acpi_thermal.c 91215 2002-02-25 02:21:22Z msmith $ 2867761Smsmith */ 2967761Smsmith 3067761Smsmith#include "opt_acpi.h" 3167761Smsmith#include <sys/param.h> 3267761Smsmith#include <sys/kernel.h> 3391126Smsmith#include <sys/kthread.h> 3491215Smsmith#include <sys/lock.h> 3591215Smsmith#include <sys/mutex.h> 3667761Smsmith#include <sys/bus.h> 3791126Smsmith#include <sys/proc.h> 3878915Smsmith#include <sys/reboot.h> 3979283Smsmith#include <sys/sysctl.h> 4091126Smsmith#include <sys/unistd.h> 4167761Smsmith 4267761Smsmith#include "acpi.h" 4367761Smsmith 4467761Smsmith#include <dev/acpica/acpivar.h> 4567761Smsmith 4669744Smsmith/* 4769744Smsmith * Hooks for the ACPI CA debugging infrastructure 4869744Smsmith */ 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 5578915Smsmith#define TZ_NOTIFY_TEMPERATURE 0x80 5678915Smsmith#define TZ_NOTIFY_DEVICES 0x81 5778915Smsmith#define TZ_NOTIFY_LEVELS 0x82 5878915Smsmith 5988420Siwasaki#define TZ_POLLRATE 30 /* every 30 seconds by default */ 6078915Smsmith 6178915Smsmith#define TZ_NUMLEVELS 10 /* defined by ACPI spec */ 6279375Smsmithstruct acpi_tz_zone { 6378915Smsmith int ac[TZ_NUMLEVELS]; 6478915Smsmith ACPI_BUFFER al[TZ_NUMLEVELS]; 6578915Smsmith int crt; 6678915Smsmith int hot; 6778915Smsmith ACPI_BUFFER psl; 6878915Smsmith int psv; 6978915Smsmith int tc1; 7078915Smsmith int tc2; 7178915Smsmith int tsp; 7278915Smsmith int tzp; 7378915Smsmith}; 7478915Smsmith 7578915Smsmith 7667761Smsmithstruct acpi_tz_softc { 7779375Smsmith device_t tz_dev; /* device handle */ 7879375Smsmith ACPI_HANDLE tz_handle; /* thermal zone handle */ 7979375Smsmith int tz_temperature; /* current temperature */ 8079375Smsmith int tz_active; /* current active cooling */ 8179375Smsmith#define TZ_ACTIVE_NONE -1 8279375Smsmith int tz_requested; /* user-requested minimum active cooling */ 8379375Smsmith int tz_thflags; /* current temperature-related flags */ 8479375Smsmith#define TZ_THFLAG_NONE 0 8579375Smsmith#define TZ_THFLAG_PSV (1<<0) 8679375Smsmith#define TZ_THFLAG_HOT (1<<2) 8779375Smsmith#define TZ_THFLAG_CRT (1<<3) 8879283Smsmith int tz_flags; 8979375Smsmith#define TZ_FLAG_NO_SCP (1<<0) /* no _SCP method */ 9079375Smsmith#define TZ_FLAG_GETPROFILE (1<<1) /* fetch powerprofile in timeout */ 9185699Siwasaki struct timespec tz_cooling_started; /* current cooling starting time */ 9279283Smsmith 9379375Smsmith struct sysctl_ctx_list tz_sysctl_ctx; /* sysctl tree */ 9479283Smsmith struct sysctl_oid *tz_sysctl_tree; 9578915Smsmith 9679375Smsmith 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); 10378999Smsmithstatic void acpi_tz_monitor(struct acpi_tz_softc *sc); 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); 10778915Smsmithstatic void acpi_tz_getparam(struct acpi_tz_softc *sc, char *node, int *data); 10879283Smsmithstatic void acpi_tz_sanity(struct acpi_tz_softc *sc, int *val, char *what); 10979375Smsmithstatic int acpi_tz_active_sysctl(SYSCTL_HANDLER_ARGS); 11071874Smsmithstatic void acpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context); 11191126Smsmithstatic void acpi_tz_timeout(struct acpi_tz_softc *sc); 11279375Smsmithstatic void acpi_tz_powerprofile(void *arg); 11371874Smsmith 11491126Smsmithstatic void acpi_tz_thread(void *arg); 11591126Smsmithstatic struct proc *acpi_tz_proc; 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 13785699Siwasakistatic int acpi_tz_min_runtime = 0;/* minimum cooling run time */ 13888420Siwasakistatic int acpi_tz_polling_rate = TZ_POLLRATE; 13985699Siwasaki 14078915Smsmith/* 14178915Smsmith * Match an ACPI thermal zone. 14278915Smsmith */ 14367761Smsmithstatic int 14467761Smsmithacpi_tz_probe(device_t dev) 14567761Smsmith{ 14678999Smsmith int result; 14778999Smsmith 14878999Smsmith ACPI_LOCK; 14978999Smsmith 15078915Smsmith /* no FUNCTION_TRACE - too noisy */ 15169744Smsmith 15269744Smsmith if ((acpi_get_type(dev) == ACPI_TYPE_THERMAL) && 15369744Smsmith !acpi_disabled("thermal")) { 15467761Smsmith device_set_desc(dev, "thermal zone"); 15578999Smsmith result = -10; 15678999Smsmith } else { 15778999Smsmith result = ENXIO; 15867761Smsmith } 15978999Smsmith ACPI_UNLOCK; 16078999Smsmith return(result); 16167761Smsmith} 16267761Smsmith 16378915Smsmith/* 16478915Smsmith * Attach to an ACPI thermal zone. 16578915Smsmith */ 16667761Smsmithstatic int 16767761Smsmithacpi_tz_attach(device_t dev) 16867761Smsmith{ 16967761Smsmith struct acpi_tz_softc *sc; 17079283Smsmith struct acpi_softc *acpi_sc; 17178915Smsmith int error; 17279283Smsmith char oidname[8]; 17367761Smsmith 17491126Smsmith ACPI_FUNCTION_TRACE(__func__); 17569744Smsmith 17678999Smsmith ACPI_LOCK; 17778999Smsmith 17867761Smsmith sc = device_get_softc(dev); 17967761Smsmith sc->tz_dev = dev; 18067761Smsmith sc->tz_handle = acpi_get_handle(dev); 18179375Smsmith sc->tz_requested = TZ_ACTIVE_NONE; 18288420Siwasaki sc->tz_tmp_updating = 0; 18367761Smsmith 18478915Smsmith /* 18578915Smsmith * Parse the current state of the thermal zone and build control 18678915Smsmith * structures. 18778915Smsmith */ 18878915Smsmith if ((error = acpi_tz_establish(sc)) != 0) 18978999Smsmith goto out; 19078915Smsmith 19178915Smsmith /* 19278915Smsmith * Register for any Notify events sent to this zone. 19378915Smsmith */ 19471874Smsmith AcpiInstallNotifyHandler(sc->tz_handle, ACPI_DEVICE_NOTIFY, 19578999Smsmith acpi_tz_notify_handler, sc); 19670271Stakawata 19771874Smsmith /* 19879283Smsmith * Create our sysctl nodes. 19979283Smsmith * 20079283Smsmith * XXX we need a mechanism for adding nodes under ACPI. 20179283Smsmith */ 20279283Smsmith if (device_get_unit(dev) == 0) { 20379283Smsmith acpi_sc = acpi_device_get_parent_softc(dev); 20479283Smsmith sysctl_ctx_init(&acpi_tz_sysctl_ctx); 20579283Smsmith acpi_tz_sysctl_tree = SYSCTL_ADD_NODE(&acpi_tz_sysctl_ctx, 20679283Smsmith SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), 20779283Smsmith OID_AUTO, "thermal", CTLFLAG_RD, 0, ""); 20885699Siwasaki SYSCTL_ADD_INT(&acpi_tz_sysctl_ctx, 20985699Siwasaki SYSCTL_CHILDREN(acpi_tz_sysctl_tree), 21085699Siwasaki OID_AUTO, "min_runtime", CTLFLAG_RD | CTLFLAG_RW, 21185699Siwasaki &acpi_tz_min_runtime, 0, "minimum cooling run time in sec"); 21288420Siwasaki SYSCTL_ADD_INT(&acpi_tz_sysctl_ctx, 21388420Siwasaki SYSCTL_CHILDREN(acpi_tz_sysctl_tree), 21488420Siwasaki OID_AUTO, "polling_rate", CTLFLAG_RD | CTLFLAG_RW, 21588420Siwasaki &acpi_tz_polling_rate, 0, "monitor polling rate"); 21679283Smsmith } 21779283Smsmith sysctl_ctx_init(&sc->tz_sysctl_ctx); 21879283Smsmith sprintf(oidname, "tz%d", device_get_unit(dev)); 21979283Smsmith sc->tz_sysctl_tree = SYSCTL_ADD_NODE(&sc->tz_sysctl_ctx, 22079283Smsmith SYSCTL_CHILDREN(acpi_tz_sysctl_tree), OID_AUTO, 22179283Smsmith oidname, CTLFLAG_RD, 0, ""); 22279283Smsmith SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 22379283Smsmith OID_AUTO, "temperature", CTLFLAG_RD, 22479283Smsmith &sc->tz_temperature, 0, "current thermal zone temperature"); 22579375Smsmith SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 22679375Smsmith OID_AUTO, "active", CTLTYPE_INT | CTLFLAG_RW, 22779375Smsmith sc, 0, acpi_tz_active_sysctl, "I", ""); 22879375Smsmith 22979283Smsmith SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 23079375Smsmith OID_AUTO, "thermal_flags", CTLFLAG_RD, 23179375Smsmith &sc->tz_thflags, 0, "thermal zone flags"); 23279283Smsmith SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 23379283Smsmith OID_AUTO, "_PSV", CTLFLAG_RD, 23479375Smsmith &sc->tz_zone.psv, 0, ""); 23579283Smsmith SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 23679283Smsmith OID_AUTO, "_HOT", CTLFLAG_RD, 23779375Smsmith &sc->tz_zone.hot, 0, ""); 23879283Smsmith SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 23979283Smsmith OID_AUTO, "_CRT", CTLFLAG_RD, 24079375Smsmith &sc->tz_zone.crt, 0, ""); 24186399Siwasaki SYSCTL_ADD_OPAQUE(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 24286399Siwasaki OID_AUTO, "_ACx", CTLFLAG_RD, &sc->tz_zone.ac, 24386399Siwasaki sizeof(sc->tz_zone.ac), "I", ""); 24479283Smsmith 24586399Siwasaki 24679283Smsmith /* 24779375Smsmith * Register our power profile event handler, and flag it for a manual 24879375Smsmith * invocation by our timeout. We defer it like this so that the rest 24979375Smsmith * of the subsystem has time to come up. 25079375Smsmith */ 25179375Smsmith EVENTHANDLER_REGISTER(powerprofile_change, acpi_tz_powerprofile, sc, 0); 25279375Smsmith sc->tz_flags |= TZ_FLAG_GETPROFILE; 25379375Smsmith 25479375Smsmith /* 25571874Smsmith * Don't bother evaluating/printing the temperature at this point; 25671874Smsmith * on many systems it'll be bogus until the EC is running. 25771874Smsmith */ 25878999Smsmith 25991126Smsmith /* 26091126Smsmith * Create our thread; we only need one, it will service all of the 26191126Smsmith * thermal zones. 26291126Smsmith */ 26391126Smsmith if (acpi_tz_proc == NULL) { 26491126Smsmith error = kthread_create(acpi_tz_thread, NULL, &acpi_tz_proc, 26591126Smsmith RFHIGHPID, "acpi_thermal"); 26691126Smsmith if (error != 0) { 26791126Smsmith device_printf(sc->tz_dev, "could not create thread - %d", error); 26891126Smsmith goto out; 26991126Smsmith } 27091126Smsmith } 27191126Smsmith 27278999Smsmith out: 27378999Smsmith ACPI_UNLOCK; 27479375Smsmith 27578999Smsmith return_VALUE(error); 27667761Smsmith} 27770271Stakawata 27878915Smsmith/* 27978915Smsmith * Parse the current state of this thermal zone and set up to use it. 28078915Smsmith * 28178915Smsmith * Note that we may have previous state, which will have to be discarded. 28278915Smsmith */ 28378915Smsmithstatic int 28478915Smsmithacpi_tz_establish(struct acpi_tz_softc *sc) 28578915Smsmith{ 28678915Smsmith ACPI_OBJECT *obj; 28778915Smsmith int i; 28878915Smsmith char nbuf[8]; 28978915Smsmith 29091126Smsmith ACPI_FUNCTION_TRACE(__func__); 29178915Smsmith 29278999Smsmith ACPI_ASSERTLOCK; 29378999Smsmith 29478915Smsmith /* 29578915Smsmith * Power everything off and erase any existing state. 29678915Smsmith */ 29778915Smsmith acpi_tz_all_off(sc); 29878915Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) 29979375Smsmith if (sc->tz_zone.al[i].Pointer != NULL) 30079375Smsmith AcpiOsFree(sc->tz_zone.al[i].Pointer); 30179375Smsmith if (sc->tz_zone.psl.Pointer != NULL) 30279375Smsmith AcpiOsFree(sc->tz_zone.psl.Pointer); 30379375Smsmith bzero(&sc->tz_zone, sizeof(sc->tz_zone)); 30478915Smsmith 30578915Smsmith /* 30678915Smsmith * Evaluate thermal zone parameters. 30778915Smsmith */ 30878915Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) { 30978915Smsmith sprintf(nbuf, "_AC%d", i); 31079375Smsmith acpi_tz_getparam(sc, nbuf, &sc->tz_zone.ac[i]); 31178915Smsmith sprintf(nbuf, "_AL%d", i); 31291126Smsmith sc->tz_zone.al[i].Length = ACPI_ALLOCATE_BUFFER; 31391126Smsmith sc->tz_zone.al[i].Pointer = NULL; 31491126Smsmith AcpiEvaluateObject(sc->tz_handle, nbuf, NULL, &sc->tz_zone.al[i]); 31579375Smsmith obj = (ACPI_OBJECT *)sc->tz_zone.al[i].Pointer; 31678915Smsmith if (obj != NULL) { 31778915Smsmith /* should be a package containing a list of power objects */ 31878915Smsmith if (obj->Type != ACPI_TYPE_PACKAGE) { 31978915Smsmith device_printf(sc->tz_dev, "%s has unknown object type %d, rejecting\n", 32078915Smsmith nbuf, obj->Type); 32178915Smsmith return_VALUE(ENXIO); 32278915Smsmith } 32378915Smsmith } 32478915Smsmith } 32579375Smsmith acpi_tz_getparam(sc, "_CRT", &sc->tz_zone.crt); 32679375Smsmith acpi_tz_getparam(sc, "_HOT", &sc->tz_zone.hot); 32791126Smsmith sc->tz_zone.psl.Length = ACPI_ALLOCATE_BUFFER; 32891126Smsmith sc->tz_zone.psl.Pointer = NULL; 32991126Smsmith AcpiEvaluateObject(sc->tz_handle, "_PSL", NULL, &sc->tz_zone.psl); 33079375Smsmith acpi_tz_getparam(sc, "_PSV", &sc->tz_zone.psv); 33179375Smsmith acpi_tz_getparam(sc, "_TC1", &sc->tz_zone.tc1); 33279375Smsmith acpi_tz_getparam(sc, "_TC2", &sc->tz_zone.tc2); 33379375Smsmith acpi_tz_getparam(sc, "_TSP", &sc->tz_zone.tsp); 33479375Smsmith acpi_tz_getparam(sc, "_TZP", &sc->tz_zone.tzp); 33578915Smsmith 33678915Smsmith /* 33779283Smsmith * Sanity-check the values we've been given. 33879283Smsmith * 33979283Smsmith * XXX what do we do about systems that give us the same value for 34079283Smsmith * more than one of these setpoints? 34179283Smsmith */ 34279375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.crt, "_CRT"); 34379375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.hot, "_HOT"); 34479375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.psv, "_PSV"); 34579283Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) 34679375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.ac[i], "_ACx"); 34779283Smsmith 34879283Smsmith /* 34978915Smsmith * Power off everything that we've just been given. 35078915Smsmith */ 35178915Smsmith acpi_tz_all_off(sc); 35278915Smsmith 35378915Smsmith return_VALUE(0); 35478915Smsmith} 35578915Smsmith 35685699Siwasakistatic char *aclevel_string[] = { 35785699Siwasaki "NONE", "_AC0", "_AC1", "_AC2", "_AC3", "_AC4", 35885699Siwasaki "_AC5", "_AC6", "_AC7", "_AC8", "_AC9" }; 35985699Siwasaki 36085699Siwasakistatic __inline const char * 36185699Siwasakiacpi_tz_aclevel_string(int active) 36285699Siwasaki{ 36385699Siwasaki if (active < -1 || active >= TZ_NUMLEVELS) { 36485699Siwasaki return (aclevel_string[0]); 36585699Siwasaki } 36685699Siwasaki 36785699Siwasaki return (aclevel_string[active+1]); 36885699Siwasaki} 36985699Siwasaki 37078915Smsmith/* 37178915Smsmith * Evaluate the condition of a thermal zone, take appropriate actions. 37278915Smsmith */ 37371874Smsmithstatic void 37478915Smsmithacpi_tz_monitor(struct acpi_tz_softc *sc) 37571874Smsmith{ 37679283Smsmith int temp; 37778915Smsmith int i; 37879283Smsmith int newactive, newflags; 37985699Siwasaki struct timespec curtime; 38086399Siwasaki ACPI_STATUS status; 38170271Stakawata 38291126Smsmith ACPI_FUNCTION_TRACE(__func__); 38370271Stakawata 38478999Smsmith ACPI_ASSERTLOCK; 38578999Smsmith 38688420Siwasaki if (sc->tz_tmp_updating) { 38788420Siwasaki goto out; 38888420Siwasaki } 38988420Siwasaki sc->tz_tmp_updating = 1; 39088420Siwasaki 39178915Smsmith /* 39278915Smsmith * Get the current temperature. 39378915Smsmith */ 39491126Smsmith if (ACPI_FAILURE(status = acpi_EvaluateInteger(sc->tz_handle, "_TMP", &temp))) { 39586552Siwasaki ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 39686552Siwasaki "error fetching current temperature -- %s\n", 39786552Siwasaki AcpiFormatException(status)); 39878915Smsmith /* XXX disable zone? go to max cooling? */ 39988420Siwasaki goto out; 40071874Smsmith } 40188420Siwasaki 40282372Smsmith ACPI_DEBUG_PRINT((ACPI_DB_VALUES, "got %d.%dC\n", TZ_KELVTOC(temp))); 40379283Smsmith sc->tz_temperature = temp; 40478915Smsmith 40578915Smsmith /* 40678915Smsmith * Work out what we ought to be doing right now. 40779283Smsmith * 40879283Smsmith * Note that the _ACx levels sort from hot to cold. 40978915Smsmith */ 41079283Smsmith newactive = TZ_ACTIVE_NONE; 41179375Smsmith for (i = TZ_NUMLEVELS - 1; i >= 0; i--) { 41279375Smsmith if ((sc->tz_zone.ac[i] != -1) && (temp >= sc->tz_zone.ac[i])) { 41379283Smsmith newactive = i; 41482967Siwasaki if (sc->tz_active != newactive) { 41586552Siwasaki ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 41686552Siwasaki "_AC%d: temperature %d.%d >= setpoint %d.%d\n", i, 41786552Siwasaki TZ_KELVTOC(temp), TZ_KELVTOC(sc->tz_zone.ac[i])); 41885699Siwasaki getnanotime(&sc->tz_cooling_started); 41982967Siwasaki } 42079375Smsmith } 42179375Smsmith } 42279283Smsmith 42385699Siwasaki /* 42485699Siwasaki * We are going to get _ACx level down (colder side), but give a guaranteed 42585699Siwasaki * minimum cooling run time if requested. 42685699Siwasaki */ 42785699Siwasaki if (acpi_tz_min_runtime > 0 && sc->tz_active != TZ_ACTIVE_NONE && 42885699Siwasaki (newactive == TZ_ACTIVE_NONE || newactive > sc->tz_active)) { 42985699Siwasaki getnanotime(&curtime); 43085699Siwasaki timespecsub(&curtime, &sc->tz_cooling_started); 43185699Siwasaki if (curtime.tv_sec < acpi_tz_min_runtime) { 43285699Siwasaki newactive = sc->tz_active; 43385699Siwasaki } 43485699Siwasaki } 43585699Siwasaki 43679375Smsmith /* handle user override of active mode */ 43779375Smsmith if (sc->tz_requested > newactive) 43879375Smsmith newactive = sc->tz_requested; 43978915Smsmith 44079375Smsmith /* update temperature-related flags */ 44179375Smsmith newflags = TZ_THFLAG_NONE; 44279375Smsmith if ((sc->tz_zone.psv != -1) && (temp >= sc->tz_zone.psv)) 44379375Smsmith newflags |= TZ_THFLAG_PSV; 44479375Smsmith if ((sc->tz_zone.hot != -1) && (temp >= sc->tz_zone.hot)) 44579375Smsmith newflags |= TZ_THFLAG_HOT; 44679375Smsmith if ((sc->tz_zone.crt != -1) && (temp >= sc->tz_zone.crt)) 44779375Smsmith newflags |= TZ_THFLAG_CRT; 44879375Smsmith 44978915Smsmith /* 45079283Smsmith * If the active cooling state has changed, we have to switch things. 45178915Smsmith */ 45279283Smsmith if (newactive != sc->tz_active) { 45378915Smsmith 45479283Smsmith /* turn off the cooling devices that are on, if any are */ 45579283Smsmith if (sc->tz_active != TZ_ACTIVE_NONE) 45679375Smsmith acpi_ForeachPackageObject((ACPI_OBJECT *)sc->tz_zone.al[sc->tz_active].Pointer, 45779283Smsmith acpi_tz_switch_cooler_off, sc); 45878915Smsmith 45979283Smsmith /* turn on cooling devices that are required, if any are */ 46079283Smsmith if (newactive != TZ_ACTIVE_NONE) 46179375Smsmith acpi_ForeachPackageObject((ACPI_OBJECT *)sc->tz_zone.al[newactive].Pointer, 46279283Smsmith acpi_tz_switch_cooler_on, sc); 46386552Siwasaki ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 46486552Siwasaki "switched from %s to %s: %d.%dC\n", 46586552Siwasaki acpi_tz_aclevel_string(sc->tz_active), 46686552Siwasaki acpi_tz_aclevel_string(newactive), TZ_KELVTOC(temp)); 46779283Smsmith sc->tz_active = newactive; 46879283Smsmith } 46978915Smsmith 47078915Smsmith /* 47179283Smsmith * XXX (de)activate any passive cooling that may be required. 47278915Smsmith */ 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 */ 48079375Smsmith if ((newflags & (TZ_THFLAG_HOT | TZ_THFLAG_CRT)) && 48179375Smsmith !(sc->tz_thflags & (TZ_THFLAG_HOT | TZ_THFLAG_CRT))) { 48279283Smsmith device_printf(sc->tz_dev, "WARNING - current temperature (%d.%dC) exceeds system limits\n", 48379283Smsmith TZ_KELVTOC(sc->tz_temperature), sc->tz_temperature); 48479283Smsmith /* shutdown_nice(RB_POWEROFF);*/ 48578915Smsmith } 48679375Smsmith sc->tz_thflags = newflags; 48778915Smsmith 48888420Siwasakiout: 48988420Siwasaki sc->tz_tmp_updating = 0; 49071874Smsmith return_VOID; 49171874Smsmith} 49270271Stakawata 49378915Smsmith/* 49478915Smsmith * Turn off all the cooling devices. 49578915Smsmith */ 49671874Smsmithstatic void 49778915Smsmithacpi_tz_all_off(struct acpi_tz_softc *sc) 49878915Smsmith{ 49978915Smsmith int i; 50078915Smsmith 50191126Smsmith ACPI_FUNCTION_TRACE(__func__); 50278999Smsmith 50378999Smsmith ACPI_ASSERTLOCK; 50478915Smsmith 50578915Smsmith /* 50679375Smsmith * Scan all the _ALx objects, and turn them all off. 50778915Smsmith */ 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; 52178915Smsmith return_VOID; 52278915Smsmith} 52378915Smsmith 52478915Smsmith/* 52578915Smsmith * Given an object, verify that it's a reference to a device of some sort, 52678915Smsmith * and try to switch it off. 52778915Smsmith */ 52878915Smsmithstatic void 52978915Smsmithacpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg) 53078915Smsmith{ 53179375Smsmith ACPI_HANDLE cooler; 53278915Smsmith 53391126Smsmith ACPI_FUNCTION_TRACE(__func__); 53478915Smsmith 53578999Smsmith ACPI_ASSERTLOCK; 53678999Smsmith 53778915Smsmith switch(obj->Type) { 53878915Smsmith case ACPI_TYPE_STRING: 53982372Smsmith ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s off\n", obj->String.Pointer)); 54078915Smsmith 54178915Smsmith /* 54278915Smsmith * Find the handle for the device and turn it off. 54378915Smsmith * The String object here seems to contain a fully-qualified path, so we 54478915Smsmith * don't have to search for it in our parents. 54578915Smsmith * 54678915Smsmith * XXX This may not always be the case. 54778915Smsmith */ 54891126Smsmith if (ACPI_SUCCESS(AcpiGetHandle(NULL, obj->String.Pointer, &cooler))) 54978915Smsmith acpi_pwr_switch_consumer(cooler, ACPI_STATE_D3); 55078915Smsmith break; 55178915Smsmith 55278915Smsmith default: 55382372Smsmith ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to handle unsupported object type %d\n", 55482372Smsmith obj->Type)); 55578915Smsmith break; 55678915Smsmith } 55779375Smsmith return_VOID; 55878915Smsmith} 55978915Smsmith 56078915Smsmith/* 56178915Smsmith * Given an object, verify that it's a reference to a device of some sort, 56278915Smsmith * and try to switch it on. 56378915Smsmith * 56478915Smsmith * XXX replication of off/on function code is bad, mmmkay? 56578915Smsmith */ 56678915Smsmithstatic void 56778915Smsmithacpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg) 56878915Smsmith{ 56978915Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg; 57078999Smsmith ACPI_HANDLE cooler; 57179375Smsmith ACPI_STATUS status; 57279375Smsmith 57391126Smsmith ACPI_FUNCTION_TRACE(__func__); 57478915Smsmith 57578999Smsmith ACPI_ASSERTLOCK; 57678999Smsmith 57778915Smsmith switch(obj->Type) { 57878915Smsmith case ACPI_TYPE_STRING: 57982372Smsmith ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s on\n", obj->String.Pointer)); 58078915Smsmith 58178999Smsmith /* 58278999Smsmith * Find the handle for the device and turn it off. 58378999Smsmith * The String object here seems to contain a fully-qualified path, so we 58478999Smsmith * don't have to search for it in our parents. 58578999Smsmith * 58678999Smsmith * XXX This may not always be the case. 58778999Smsmith */ 58891126Smsmith if (ACPI_SUCCESS(AcpiGetHandle(NULL, obj->String.Pointer, &cooler))) { 58979375Smsmith if (ACPI_FAILURE(status = acpi_pwr_switch_consumer(cooler, ACPI_STATE_D0))) { 59086552Siwasaki ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 59186552Siwasaki "failed to activate %s - %s\n", 59286552Siwasaki obj->String.Pointer, AcpiFormatException(status)); 59379375Smsmith } 59479375Smsmith } else { 59586552Siwasaki ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 59686552Siwasaki "couldn't find %s\n", obj->String.Pointer); 59779375Smsmith } 59878915Smsmith break; 59978915Smsmith 60078915Smsmith default: 60182372Smsmith ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to handle unsupported object type %d\n", 60282372Smsmith obj->Type)); 60378915Smsmith break; 60478915Smsmith } 60578915Smsmith return_VOID; 60678915Smsmith} 60778915Smsmith 60878915Smsmith/* 60978915Smsmith * Read/debug-print a parameter, default it to -1. 61078915Smsmith */ 61178915Smsmithstatic void 61278915Smsmithacpi_tz_getparam(struct acpi_tz_softc *sc, char *node, int *data) 61378915Smsmith{ 61478915Smsmith 61591126Smsmith ACPI_FUNCTION_TRACE(__func__); 61678915Smsmith 61778999Smsmith ACPI_ASSERTLOCK; 61878999Smsmith 61991126Smsmith if (ACPI_FAILURE(acpi_EvaluateInteger(sc->tz_handle, node, data))) { 62078915Smsmith *data = -1; 62178915Smsmith } else { 62282372Smsmith ACPI_DEBUG_PRINT((ACPI_DB_VALUES, "%s.%s = %d\n", acpi_name(sc->tz_handle), 62382372Smsmith node, *data)); 62478915Smsmith } 62578915Smsmith return_VOID; 62678915Smsmith} 62779283Smsmith 62879283Smsmith/* 62979283Smsmith * Sanity-check a temperature value. Assume that setpoints 63079283Smsmith * should be between 0C and 150C. 63179283Smsmith */ 63279283Smsmithstatic void 63379283Smsmithacpi_tz_sanity(struct acpi_tz_softc *sc, int *val, char *what) 63479283Smsmith{ 63579283Smsmith if ((*val != -1) && ((*val < TZ_ZEROC) || (*val > (TZ_ZEROC + 1500)))) { 63679283Smsmith device_printf(sc->tz_dev, "%s value is absurd, ignored (%d.%dC)\n", 63779283Smsmith what, TZ_KELVTOC(*val)); 63879283Smsmith *val = -1; 63979283Smsmith } 64079283Smsmith} 64179375Smsmith 64279375Smsmith/* 64379375Smsmith * Respond to a sysctl on the active state node. 64479375Smsmith */ 64579375Smsmithstatic int 64679375Smsmithacpi_tz_active_sysctl(SYSCTL_HANDLER_ARGS) 64779375Smsmith{ 64879375Smsmith struct acpi_tz_softc *sc; 64979375Smsmith int active; 65079375Smsmith int error; 65179375Smsmith 65279375Smsmith ACPI_LOCK; 65379375Smsmith 65479375Smsmith sc = (struct acpi_tz_softc *)oidp->oid_arg1; 65579375Smsmith active = sc->tz_active; 65679375Smsmith error = sysctl_handle_int(oidp, &active, 0, req); 65779375Smsmith 65879375Smsmith /* error or no new value */ 65979375Smsmith if ((error != 0) || (req->newptr == NULL)) 66079375Smsmith goto out; 66178915Smsmith 66279375Smsmith /* range check */ 66379375Smsmith if ((active < -1) || (active >= TZ_NUMLEVELS)) { 66479375Smsmith error = EINVAL; 66579375Smsmith goto out; 66679375Smsmith } 66779375Smsmith 66879375Smsmith /* set new preferred level and re-switch */ 66979375Smsmith sc->tz_requested = active; 67079375Smsmith acpi_tz_monitor(sc); 67179375Smsmith 67279375Smsmith out: 67379375Smsmith ACPI_UNLOCK; 67479375Smsmith return(error); 67579375Smsmith} 67679375Smsmith 67778915Smsmith/* 67878915Smsmith * Respond to a Notify event sent to the zone. 67978915Smsmith */ 68078915Smsmithstatic void 68171874Smsmithacpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context) 68271874Smsmith{ 68378915Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)context; 68478915Smsmith 68591126Smsmith ACPI_FUNCTION_TRACE(__func__); 68670271Stakawata 68778999Smsmith ACPI_ASSERTLOCK; 68878999Smsmith 68978915Smsmith switch(notify) { 69078915Smsmith case TZ_NOTIFY_TEMPERATURE: 69178999Smsmith /* temperature change occurred */ 69278999Smsmith AcpiOsQueueForExecution(OSD_PRIORITY_HIGH, (OSD_EXECUTION_CALLBACK)acpi_tz_monitor, sc); 69378915Smsmith break; 69478915Smsmith case TZ_NOTIFY_DEVICES: 69578915Smsmith case TZ_NOTIFY_LEVELS: 69678999Smsmith /* zone devices/setpoints changed */ 69778999Smsmith AcpiOsQueueForExecution(OSD_PRIORITY_HIGH, (OSD_EXECUTION_CALLBACK)acpi_tz_establish, sc); 69878915Smsmith break; 69978915Smsmith default: 70086552Siwasaki ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 70186552Siwasaki "unknown Notify event 0x%x\n", notify); 70278915Smsmith break; 70371874Smsmith } 70471874Smsmith return_VOID; 70571874Smsmith} 70670271Stakawata 70778915Smsmith/* 70878915Smsmith * Poll the thermal zone. 70978915Smsmith */ 71078915Smsmithstatic void 71191126Smsmithacpi_tz_timeout(struct acpi_tz_softc *sc) 71278915Smsmith{ 71378915Smsmith 71479375Smsmith /* do we need to get the power profile settings? */ 71579375Smsmith if (sc->tz_flags & TZ_FLAG_GETPROFILE) { 71691126Smsmith acpi_tz_powerprofile((void *)sc); 71779375Smsmith sc->tz_flags &= ~TZ_FLAG_GETPROFILE; 71879375Smsmith } 71979375Smsmith 72091126Smsmith ACPI_ASSERTLOCK; 72178915Smsmith 72291126Smsmith /* check the current temperature and take action based on it */ 72391126Smsmith acpi_tz_monitor(sc); 72491126Smsmith 72578915Smsmith /* XXX passive cooling actions? */ 72678915Smsmith} 72779375Smsmith 72879375Smsmith/* 72979375Smsmith * System power profile may have changed; fetch and notify the 73079375Smsmith * thermal zone accordingly. 73179375Smsmith * 73279375Smsmith * Since this can be called from an arbitrary eventhandler, it needs 73379375Smsmith * to get the ACPI lock itself. 73479375Smsmith */ 73579375Smsmithstatic void 73679375Smsmithacpi_tz_powerprofile(void *arg) 73779375Smsmith{ 73879375Smsmith ACPI_OBJECT_LIST args; 73979375Smsmith ACPI_OBJECT obj; 74079375Smsmith ACPI_STATUS status; 74179375Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg; 74279375Smsmith 74379375Smsmith ACPI_LOCK; 74479375Smsmith 74579375Smsmith /* check that we haven't decided there's no _SCP method */ 74679375Smsmith if (!(sc->tz_flags & TZ_FLAG_NO_SCP)) { 74779375Smsmith 74879375Smsmith /* call _SCP to set the new profile */ 74979375Smsmith obj.Type = ACPI_TYPE_INTEGER; 75079375Smsmith obj.Integer.Value = (powerprofile_get_state() == POWERPROFILE_PERFORMANCE) ? 0 : 1; 75179375Smsmith args.Count = 1; 75279375Smsmith args.Pointer = &obj; 75379375Smsmith if (ACPI_FAILURE(status = AcpiEvaluateObject(sc->tz_handle, "_SCP", &args, NULL))) { 75479385Smsmith if (status != AE_NOT_FOUND) 75586552Siwasaki ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 75686552Siwasaki "can't evaluate %s._SCP - %s\n", acpi_name(sc->tz_handle), 75786552Siwasaki AcpiFormatException(status)); 75879375Smsmith sc->tz_flags |= TZ_FLAG_NO_SCP; 75979375Smsmith } else { 76079375Smsmith /* we have to re-evaluate the entire zone now */ 76179375Smsmith AcpiOsQueueForExecution(OSD_PRIORITY_HIGH, (OSD_EXECUTION_CALLBACK)acpi_tz_establish, sc); 76279375Smsmith } 76379375Smsmith } 76479375Smsmith ACPI_UNLOCK; 76579375Smsmith} 76679375Smsmith 76791126Smsmith/* 76891126Smsmith * Thermal zone monitor thread. 76991126Smsmith */ 77091126Smsmithstatic void 77191126Smsmithacpi_tz_thread(void *arg) 77291126Smsmith{ 77391126Smsmith device_t *devs; 77491126Smsmith int devcount, i; 77591126Smsmith 77691126Smsmith ACPI_FUNCTION_TRACE(__func__); 77791126Smsmith 77891126Smsmith 77991126Smsmith devs = NULL; 78091126Smsmith devcount = 0; 78191126Smsmith 78291126Smsmith for (;;) { 78391126Smsmith tsleep(&acpi_tz_proc, PZERO, "nothing", hz * acpi_tz_polling_rate); 78491126Smsmith 78591215Smsmith mtx_lock(&Giant); 78691215Smsmith 78791126Smsmith if (devcount == 0) 78891126Smsmith devclass_get_devices(acpi_tz_devclass, &devs, &devcount); 78991126Smsmith 79091126Smsmith ACPI_LOCK; 79191126Smsmith for (i = 0; i < devcount; i++) 79291126Smsmith acpi_tz_timeout(device_get_softc(devs[i])); 79391126Smsmith ACPI_UNLOCK; 79491215Smsmith 79591215Smsmith mtx_unlock(&Giant); 79691126Smsmith } 79791126Smsmith} 798