acpi_thermal.c revision 85699
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 85699 2001-10-29 18:09:43Z iwasaki $ 2867761Smsmith */ 2967761Smsmith 3067761Smsmith#include "opt_acpi.h" 3167761Smsmith#include <sys/param.h> 3267761Smsmith#include <sys/kernel.h> 3367761Smsmith#include <sys/bus.h> 3478915Smsmith#include <sys/reboot.h> 3579283Smsmith#include <sys/sysctl.h> 3667761Smsmith 3767761Smsmith#include "acpi.h" 3867761Smsmith 3967761Smsmith#include <dev/acpica/acpivar.h> 4067761Smsmith 4169744Smsmith/* 4269744Smsmith * Hooks for the ACPI CA debugging infrastructure 4369744Smsmith */ 4478999Smsmith#define _COMPONENT ACPI_THERMAL 4569744SmsmithMODULE_NAME("THERMAL") 4669744Smsmith 4771874Smsmith#define TZ_ZEROC 2732 4871874Smsmith#define TZ_KELVTOC(x) (((x) - TZ_ZEROC) / 10), (((x) - TZ_ZEROC) % 10) 4967761Smsmith 5085699Siwasaki#define TZ_DPRINT(dev, x...) do { \ 5185699Siwasaki if (acpi_get_verbose(acpi_device_get_parent_softc(dev))) \ 5285699Siwasaki device_printf(dev, x); \ 5385699Siwasaki} while (0) 5485699Siwasaki 5578915Smsmith#define TZ_NOTIFY_TEMPERATURE 0x80 5678915Smsmith#define TZ_NOTIFY_DEVICES 0x81 5778915Smsmith#define TZ_NOTIFY_LEVELS 0x82 5878915Smsmith 5978915Smsmith#define TZ_POLLRATE (hz * 10) /* every ten seconds */ 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 struct callout_handle tz_timeout; /* poll routine handle */ 8079375Smsmith int tz_temperature; /* current temperature */ 8179375Smsmith int tz_active; /* current active cooling */ 8279375Smsmith#define TZ_ACTIVE_NONE -1 8379375Smsmith int tz_requested; /* user-requested minimum active cooling */ 8479375Smsmith int tz_thflags; /* current temperature-related flags */ 8579375Smsmith#define TZ_THFLAG_NONE 0 8679375Smsmith#define TZ_THFLAG_PSV (1<<0) 8779375Smsmith#define TZ_THFLAG_HOT (1<<2) 8879375Smsmith#define TZ_THFLAG_CRT (1<<3) 8979283Smsmith int tz_flags; 9079375Smsmith#define TZ_FLAG_NO_SCP (1<<0) /* no _SCP method */ 9179375Smsmith#define TZ_FLAG_GETPROFILE (1<<1) /* fetch powerprofile in timeout */ 9285699Siwasaki struct timespec tz_cooling_started; /* current cooling starting time */ 9379283Smsmith 9479375Smsmith struct sysctl_ctx_list tz_sysctl_ctx; /* sysctl tree */ 9579283Smsmith struct sysctl_oid *tz_sysctl_tree; 9678915Smsmith 9779375Smsmith struct acpi_tz_zone tz_zone; /* thermal zone parameters */ 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); 11178915Smsmithstatic void acpi_tz_timeout(void *arg); 11279375Smsmithstatic void acpi_tz_powerprofile(void *arg); 11371874Smsmith 11467761Smsmithstatic device_method_t acpi_tz_methods[] = { 11567761Smsmith /* Device interface */ 11667761Smsmith DEVMETHOD(device_probe, acpi_tz_probe), 11767761Smsmith DEVMETHOD(device_attach, acpi_tz_attach), 11867761Smsmith 11967761Smsmith {0, 0} 12067761Smsmith}; 12167761Smsmith 12267761Smsmithstatic driver_t acpi_tz_driver = { 12367761Smsmith "acpi_tz", 12467761Smsmith acpi_tz_methods, 12567761Smsmith sizeof(struct acpi_tz_softc), 12667761Smsmith}; 12767761Smsmith 12867761Smsmithdevclass_t acpi_tz_devclass; 12967761SmsmithDRIVER_MODULE(acpi_tz, acpi, acpi_tz_driver, acpi_tz_devclass, 0, 0); 13067761Smsmith 13179283Smsmithstatic struct sysctl_ctx_list acpi_tz_sysctl_ctx; 13279283Smsmithstatic struct sysctl_oid *acpi_tz_sysctl_tree; 13379283Smsmith 13485699Siwasakistatic int acpi_tz_min_runtime = 0;/* minimum cooling run time */ 13585699Siwasaki 13678915Smsmith/* 13778915Smsmith * Match an ACPI thermal zone. 13878915Smsmith */ 13967761Smsmithstatic int 14067761Smsmithacpi_tz_probe(device_t dev) 14167761Smsmith{ 14278999Smsmith int result; 14378999Smsmith 14478999Smsmith ACPI_LOCK; 14578999Smsmith 14678915Smsmith /* no FUNCTION_TRACE - too noisy */ 14769744Smsmith 14869744Smsmith if ((acpi_get_type(dev) == ACPI_TYPE_THERMAL) && 14969744Smsmith !acpi_disabled("thermal")) { 15067761Smsmith device_set_desc(dev, "thermal zone"); 15178999Smsmith result = -10; 15278999Smsmith } else { 15378999Smsmith result = ENXIO; 15467761Smsmith } 15578999Smsmith ACPI_UNLOCK; 15678999Smsmith return(result); 15767761Smsmith} 15867761Smsmith 15978915Smsmith/* 16078915Smsmith * Attach to an ACPI thermal zone. 16178915Smsmith */ 16267761Smsmithstatic int 16367761Smsmithacpi_tz_attach(device_t dev) 16467761Smsmith{ 16567761Smsmith struct acpi_tz_softc *sc; 16679283Smsmith struct acpi_softc *acpi_sc; 16778915Smsmith int error; 16879283Smsmith char oidname[8]; 16979283Smsmith int i; 17067761Smsmith 17177432Smsmith FUNCTION_TRACE(__func__); 17269744Smsmith 17378999Smsmith ACPI_LOCK; 17478999Smsmith 17567761Smsmith sc = device_get_softc(dev); 17667761Smsmith sc->tz_dev = dev; 17767761Smsmith sc->tz_handle = acpi_get_handle(dev); 17879375Smsmith sc->tz_requested = TZ_ACTIVE_NONE; 17967761Smsmith 18078915Smsmith /* 18178915Smsmith * Parse the current state of the thermal zone and build control 18278915Smsmith * structures. 18378915Smsmith */ 18478915Smsmith if ((error = acpi_tz_establish(sc)) != 0) 18578999Smsmith goto out; 18678915Smsmith 18778915Smsmith /* 18878915Smsmith * Register for any Notify events sent to this zone. 18978915Smsmith */ 19071874Smsmith AcpiInstallNotifyHandler(sc->tz_handle, ACPI_DEVICE_NOTIFY, 19178999Smsmith acpi_tz_notify_handler, sc); 19270271Stakawata 19371874Smsmith /* 19479283Smsmith * Create our sysctl nodes. 19579283Smsmith * 19679283Smsmith * XXX we need a mechanism for adding nodes under ACPI. 19779283Smsmith */ 19879283Smsmith if (device_get_unit(dev) == 0) { 19979283Smsmith acpi_sc = acpi_device_get_parent_softc(dev); 20079283Smsmith sysctl_ctx_init(&acpi_tz_sysctl_ctx); 20179283Smsmith acpi_tz_sysctl_tree = SYSCTL_ADD_NODE(&acpi_tz_sysctl_ctx, 20279283Smsmith SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), 20379283Smsmith OID_AUTO, "thermal", CTLFLAG_RD, 0, ""); 20485699Siwasaki SYSCTL_ADD_INT(&acpi_tz_sysctl_ctx, 20585699Siwasaki SYSCTL_CHILDREN(acpi_tz_sysctl_tree), 20685699Siwasaki OID_AUTO, "min_runtime", CTLFLAG_RD | CTLFLAG_RW, 20785699Siwasaki &acpi_tz_min_runtime, 0, "minimum cooling run time in sec"); 20879283Smsmith } 20979283Smsmith sysctl_ctx_init(&sc->tz_sysctl_ctx); 21079283Smsmith sprintf(oidname, "tz%d", device_get_unit(dev)); 21179283Smsmith sc->tz_sysctl_tree = SYSCTL_ADD_NODE(&sc->tz_sysctl_ctx, 21279283Smsmith SYSCTL_CHILDREN(acpi_tz_sysctl_tree), OID_AUTO, 21379283Smsmith oidname, CTLFLAG_RD, 0, ""); 21479283Smsmith SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 21579283Smsmith OID_AUTO, "temperature", CTLFLAG_RD, 21679283Smsmith &sc->tz_temperature, 0, "current thermal zone temperature"); 21779375Smsmith SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 21879375Smsmith OID_AUTO, "active", CTLTYPE_INT | CTLFLAG_RW, 21979375Smsmith sc, 0, acpi_tz_active_sysctl, "I", ""); 22079375Smsmith 22179283Smsmith SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 22279375Smsmith OID_AUTO, "thermal_flags", CTLFLAG_RD, 22379375Smsmith &sc->tz_thflags, 0, "thermal zone flags"); 22479283Smsmith SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 22579283Smsmith OID_AUTO, "_PSV", CTLFLAG_RD, 22679375Smsmith &sc->tz_zone.psv, 0, ""); 22779283Smsmith SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 22879283Smsmith OID_AUTO, "_HOT", CTLFLAG_RD, 22979375Smsmith &sc->tz_zone.hot, 0, ""); 23079283Smsmith SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 23179283Smsmith OID_AUTO, "_CRT", CTLFLAG_RD, 23279375Smsmith &sc->tz_zone.crt, 0, ""); 23379283Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) { 23479283Smsmith sprintf(oidname, "_AC%d", i); 23579283Smsmith SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 23679283Smsmith OID_AUTO, oidname, CTLFLAG_RD, 23779375Smsmith &sc->tz_zone.ac[i], 0, ""); 23879283Smsmith } 23979283Smsmith 24079283Smsmith /* 24179375Smsmith * Register our power profile event handler, and flag it for a manual 24279375Smsmith * invocation by our timeout. We defer it like this so that the rest 24379375Smsmith * of the subsystem has time to come up. 24479375Smsmith */ 24579375Smsmith EVENTHANDLER_REGISTER(powerprofile_change, acpi_tz_powerprofile, sc, 0); 24679375Smsmith sc->tz_flags |= TZ_FLAG_GETPROFILE; 24779375Smsmith 24879375Smsmith /* 24971874Smsmith * Don't bother evaluating/printing the temperature at this point; 25071874Smsmith * on many systems it'll be bogus until the EC is running. 25171874Smsmith */ 25278999Smsmith 25378999Smsmith out: 25478999Smsmith ACPI_UNLOCK; 25579375Smsmith 25679375Smsmith /* 25779375Smsmith * Start the timeout routine, with enough delay for the rest of the 25879375Smsmith * subsystem to come up. 25979375Smsmith */ 26079375Smsmith sc->tz_timeout = timeout(acpi_tz_timeout, sc, TZ_POLLRATE); 26179375Smsmith 26278999Smsmith return_VALUE(error); 26367761Smsmith} 26470271Stakawata 26578915Smsmith/* 26678915Smsmith * Parse the current state of this thermal zone and set up to use it. 26778915Smsmith * 26878915Smsmith * Note that we may have previous state, which will have to be discarded. 26978915Smsmith */ 27078915Smsmithstatic int 27178915Smsmithacpi_tz_establish(struct acpi_tz_softc *sc) 27278915Smsmith{ 27378915Smsmith ACPI_OBJECT *obj; 27478915Smsmith int i; 27578915Smsmith char nbuf[8]; 27678915Smsmith 27778915Smsmith FUNCTION_TRACE(__func__); 27878915Smsmith 27978999Smsmith ACPI_ASSERTLOCK; 28078999Smsmith 28178915Smsmith /* 28278915Smsmith * Power everything off and erase any existing state. 28378915Smsmith */ 28478915Smsmith acpi_tz_all_off(sc); 28578915Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) 28679375Smsmith if (sc->tz_zone.al[i].Pointer != NULL) 28779375Smsmith AcpiOsFree(sc->tz_zone.al[i].Pointer); 28879375Smsmith if (sc->tz_zone.psl.Pointer != NULL) 28979375Smsmith AcpiOsFree(sc->tz_zone.psl.Pointer); 29079375Smsmith bzero(&sc->tz_zone, sizeof(sc->tz_zone)); 29178915Smsmith 29278915Smsmith /* 29378915Smsmith * Evaluate thermal zone parameters. 29478915Smsmith */ 29578915Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) { 29678915Smsmith sprintf(nbuf, "_AC%d", i); 29779375Smsmith acpi_tz_getparam(sc, nbuf, &sc->tz_zone.ac[i]); 29878915Smsmith sprintf(nbuf, "_AL%d", i); 29979375Smsmith acpi_EvaluateIntoBuffer(sc->tz_handle, nbuf, NULL, &sc->tz_zone.al[i]); 30079375Smsmith obj = (ACPI_OBJECT *)sc->tz_zone.al[i].Pointer; 30178915Smsmith if (obj != NULL) { 30278915Smsmith /* should be a package containing a list of power objects */ 30378915Smsmith if (obj->Type != ACPI_TYPE_PACKAGE) { 30478915Smsmith device_printf(sc->tz_dev, "%s has unknown object type %d, rejecting\n", 30578915Smsmith nbuf, obj->Type); 30678915Smsmith return_VALUE(ENXIO); 30778915Smsmith } 30878915Smsmith } 30978915Smsmith } 31079375Smsmith acpi_tz_getparam(sc, "_CRT", &sc->tz_zone.crt); 31179375Smsmith acpi_tz_getparam(sc, "_HOT", &sc->tz_zone.hot); 31279375Smsmith acpi_EvaluateIntoBuffer(sc->tz_handle, "_PSL", NULL, &sc->tz_zone.psl); 31379375Smsmith acpi_tz_getparam(sc, "_PSV", &sc->tz_zone.psv); 31479375Smsmith acpi_tz_getparam(sc, "_TC1", &sc->tz_zone.tc1); 31579375Smsmith acpi_tz_getparam(sc, "_TC2", &sc->tz_zone.tc2); 31679375Smsmith acpi_tz_getparam(sc, "_TSP", &sc->tz_zone.tsp); 31779375Smsmith acpi_tz_getparam(sc, "_TZP", &sc->tz_zone.tzp); 31878915Smsmith 31978915Smsmith /* 32079283Smsmith * Sanity-check the values we've been given. 32179283Smsmith * 32279283Smsmith * XXX what do we do about systems that give us the same value for 32379283Smsmith * more than one of these setpoints? 32479283Smsmith */ 32579375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.crt, "_CRT"); 32679375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.hot, "_HOT"); 32779375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.psv, "_PSV"); 32879283Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) 32979375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.ac[i], "_ACx"); 33079283Smsmith 33179283Smsmith /* 33278915Smsmith * Power off everything that we've just been given. 33378915Smsmith */ 33478915Smsmith acpi_tz_all_off(sc); 33578915Smsmith 33678915Smsmith return_VALUE(0); 33778915Smsmith} 33878915Smsmith 33985699Siwasakistatic char *aclevel_string[] = { 34085699Siwasaki "NONE", "_AC0", "_AC1", "_AC2", "_AC3", "_AC4", 34185699Siwasaki "_AC5", "_AC6", "_AC7", "_AC8", "_AC9" }; 34285699Siwasaki 34385699Siwasakistatic __inline const char * 34485699Siwasakiacpi_tz_aclevel_string(int active) 34585699Siwasaki{ 34685699Siwasaki if (active < -1 || active >= TZ_NUMLEVELS) { 34785699Siwasaki return (aclevel_string[0]); 34885699Siwasaki } 34985699Siwasaki 35085699Siwasaki return (aclevel_string[active+1]); 35185699Siwasaki} 35285699Siwasaki 35378915Smsmith/* 35478915Smsmith * Evaluate the condition of a thermal zone, take appropriate actions. 35578915Smsmith */ 35671874Smsmithstatic void 35778915Smsmithacpi_tz_monitor(struct acpi_tz_softc *sc) 35871874Smsmith{ 35979283Smsmith int temp; 36078915Smsmith int i; 36179283Smsmith int newactive, newflags; 36285699Siwasaki struct timespec curtime; 36370271Stakawata 36477432Smsmith FUNCTION_TRACE(__func__); 36570271Stakawata 36678999Smsmith ACPI_ASSERTLOCK; 36778999Smsmith 36878915Smsmith /* 36978915Smsmith * Get the current temperature. 37078915Smsmith */ 37178915Smsmith if ((acpi_EvaluateInteger(sc->tz_handle, "_TMP", &temp)) != AE_OK) { 37278915Smsmith device_printf(sc->tz_dev, "error fetching current temperature\n"); 37378915Smsmith /* XXX disable zone? go to max cooling? */ 37471874Smsmith return_VOID; 37571874Smsmith } 37682372Smsmith ACPI_DEBUG_PRINT((ACPI_DB_VALUES, "got %d.%dC\n", TZ_KELVTOC(temp))); 37779283Smsmith sc->tz_temperature = temp; 37878915Smsmith 37978915Smsmith /* 38078915Smsmith * Work out what we ought to be doing right now. 38179283Smsmith * 38279283Smsmith * Note that the _ACx levels sort from hot to cold. 38378915Smsmith */ 38479283Smsmith newactive = TZ_ACTIVE_NONE; 38579375Smsmith for (i = TZ_NUMLEVELS - 1; i >= 0; i--) { 38679375Smsmith if ((sc->tz_zone.ac[i] != -1) && (temp >= sc->tz_zone.ac[i])) { 38779283Smsmith newactive = i; 38882967Siwasaki if (sc->tz_active != newactive) { 38985699Siwasaki TZ_DPRINT(sc->tz_dev, 39085699Siwasaki "_AC%d: temperature %d.%d >= setpoint %d.%d\n", i, 39185699Siwasaki TZ_KELVTOC(temp), TZ_KELVTOC(sc->tz_zone.ac[i])); 39285699Siwasaki getnanotime(&sc->tz_cooling_started); 39382967Siwasaki } 39479375Smsmith } 39579375Smsmith } 39679283Smsmith 39785699Siwasaki /* 39885699Siwasaki * We are going to get _ACx level down (colder side), but give a guaranteed 39985699Siwasaki * minimum cooling run time if requested. 40085699Siwasaki */ 40185699Siwasaki if (acpi_tz_min_runtime > 0 && sc->tz_active != TZ_ACTIVE_NONE && 40285699Siwasaki (newactive == TZ_ACTIVE_NONE || newactive > sc->tz_active)) { 40385699Siwasaki getnanotime(&curtime); 40485699Siwasaki timespecsub(&curtime, &sc->tz_cooling_started); 40585699Siwasaki if (curtime.tv_sec < acpi_tz_min_runtime) { 40685699Siwasaki newactive = sc->tz_active; 40785699Siwasaki } 40885699Siwasaki } 40985699Siwasaki 41079375Smsmith /* handle user override of active mode */ 41179375Smsmith if (sc->tz_requested > newactive) 41279375Smsmith newactive = sc->tz_requested; 41378915Smsmith 41479375Smsmith /* update temperature-related flags */ 41579375Smsmith newflags = TZ_THFLAG_NONE; 41679375Smsmith if ((sc->tz_zone.psv != -1) && (temp >= sc->tz_zone.psv)) 41779375Smsmith newflags |= TZ_THFLAG_PSV; 41879375Smsmith if ((sc->tz_zone.hot != -1) && (temp >= sc->tz_zone.hot)) 41979375Smsmith newflags |= TZ_THFLAG_HOT; 42079375Smsmith if ((sc->tz_zone.crt != -1) && (temp >= sc->tz_zone.crt)) 42179375Smsmith newflags |= TZ_THFLAG_CRT; 42279375Smsmith 42378915Smsmith /* 42479283Smsmith * If the active cooling state has changed, we have to switch things. 42578915Smsmith */ 42679283Smsmith if (newactive != sc->tz_active) { 42778915Smsmith 42879283Smsmith /* turn off the cooling devices that are on, if any are */ 42979283Smsmith if (sc->tz_active != TZ_ACTIVE_NONE) 43079375Smsmith acpi_ForeachPackageObject((ACPI_OBJECT *)sc->tz_zone.al[sc->tz_active].Pointer, 43179283Smsmith acpi_tz_switch_cooler_off, sc); 43278915Smsmith 43379283Smsmith /* turn on cooling devices that are required, if any are */ 43479283Smsmith if (newactive != TZ_ACTIVE_NONE) 43579375Smsmith acpi_ForeachPackageObject((ACPI_OBJECT *)sc->tz_zone.al[newactive].Pointer, 43679283Smsmith acpi_tz_switch_cooler_on, sc); 43785699Siwasaki TZ_DPRINT(sc->tz_dev, "switched from %s to %s: %d.%dC\n", 43885699Siwasaki acpi_tz_aclevel_string(sc->tz_active), 43985699Siwasaki acpi_tz_aclevel_string(newactive), TZ_KELVTOC(temp)); 44079283Smsmith sc->tz_active = newactive; 44179283Smsmith } 44278915Smsmith 44378915Smsmith /* 44479283Smsmith * XXX (de)activate any passive cooling that may be required. 44578915Smsmith */ 44678915Smsmith 44778915Smsmith /* 44879283Smsmith * If we have just become _HOT or _CRT, warn the user. 44979283Smsmith * 45079283Smsmith * We should actually shut down at this point, but it's not clear 45179283Smsmith * that some systems don't actually map _CRT to the same value as _AC0. 45278915Smsmith */ 45379375Smsmith if ((newflags & (TZ_THFLAG_HOT | TZ_THFLAG_CRT)) && 45479375Smsmith !(sc->tz_thflags & (TZ_THFLAG_HOT | TZ_THFLAG_CRT))) { 45579283Smsmith device_printf(sc->tz_dev, "WARNING - current temperature (%d.%dC) exceeds system limits\n", 45679283Smsmith TZ_KELVTOC(sc->tz_temperature), sc->tz_temperature); 45779283Smsmith /* shutdown_nice(RB_POWEROFF);*/ 45878915Smsmith } 45979375Smsmith sc->tz_thflags = newflags; 46078915Smsmith 46171874Smsmith return_VOID; 46271874Smsmith} 46370271Stakawata 46478915Smsmith/* 46578915Smsmith * Turn off all the cooling devices. 46678915Smsmith */ 46771874Smsmithstatic void 46878915Smsmithacpi_tz_all_off(struct acpi_tz_softc *sc) 46978915Smsmith{ 47078915Smsmith int i; 47178915Smsmith 47278915Smsmith FUNCTION_TRACE(__func__); 47378999Smsmith 47478999Smsmith ACPI_ASSERTLOCK; 47578915Smsmith 47678915Smsmith /* 47779375Smsmith * Scan all the _ALx objects, and turn them all off. 47878915Smsmith */ 47978915Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) { 48079375Smsmith if (sc->tz_zone.al[i].Pointer == NULL) 48178915Smsmith continue; 48279375Smsmith acpi_ForeachPackageObject((ACPI_OBJECT *)sc->tz_zone.al[i].Pointer, 48378915Smsmith acpi_tz_switch_cooler_off, sc); 48478915Smsmith } 48578915Smsmith 48678915Smsmith /* 48778915Smsmith * XXX revert any passive-cooling options. 48878915Smsmith */ 48978915Smsmith 49079283Smsmith sc->tz_active = TZ_ACTIVE_NONE; 49179375Smsmith sc->tz_thflags = TZ_THFLAG_NONE; 49278915Smsmith return_VOID; 49378915Smsmith} 49478915Smsmith 49578915Smsmith/* 49678915Smsmith * Given an object, verify that it's a reference to a device of some sort, 49778915Smsmith * and try to switch it off. 49878915Smsmith */ 49978915Smsmithstatic void 50078915Smsmithacpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg) 50178915Smsmith{ 50279375Smsmith ACPI_HANDLE cooler; 50378915Smsmith 50478915Smsmith FUNCTION_TRACE(__func__); 50578915Smsmith 50678999Smsmith ACPI_ASSERTLOCK; 50778999Smsmith 50878915Smsmith switch(obj->Type) { 50978915Smsmith case ACPI_TYPE_STRING: 51082372Smsmith ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s off\n", obj->String.Pointer)); 51178915Smsmith 51278915Smsmith /* 51378915Smsmith * Find the handle for the device and turn it off. 51478915Smsmith * The String object here seems to contain a fully-qualified path, so we 51578915Smsmith * don't have to search for it in our parents. 51678915Smsmith * 51778915Smsmith * XXX This may not always be the case. 51878915Smsmith */ 51979375Smsmith if (AcpiGetHandle(NULL, obj->String.Pointer, &cooler) == AE_OK) 52078915Smsmith acpi_pwr_switch_consumer(cooler, ACPI_STATE_D3); 52178915Smsmith break; 52278915Smsmith 52378915Smsmith default: 52482372Smsmith ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to handle unsupported object type %d\n", 52582372Smsmith obj->Type)); 52678915Smsmith break; 52778915Smsmith } 52879375Smsmith return_VOID; 52978915Smsmith} 53078915Smsmith 53178915Smsmith/* 53278915Smsmith * Given an object, verify that it's a reference to a device of some sort, 53378915Smsmith * and try to switch it on. 53478915Smsmith * 53578915Smsmith * XXX replication of off/on function code is bad, mmmkay? 53678915Smsmith */ 53778915Smsmithstatic void 53878915Smsmithacpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg) 53978915Smsmith{ 54078915Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg; 54178999Smsmith ACPI_HANDLE cooler; 54279375Smsmith ACPI_STATUS status; 54379375Smsmith 54478915Smsmith FUNCTION_TRACE(__func__); 54578915Smsmith 54678999Smsmith ACPI_ASSERTLOCK; 54778999Smsmith 54878915Smsmith switch(obj->Type) { 54978915Smsmith case ACPI_TYPE_STRING: 55082372Smsmith ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s on\n", obj->String.Pointer)); 55178915Smsmith 55278999Smsmith /* 55378999Smsmith * Find the handle for the device and turn it off. 55478999Smsmith * The String object here seems to contain a fully-qualified path, so we 55578999Smsmith * don't have to search for it in our parents. 55678999Smsmith * 55778999Smsmith * XXX This may not always be the case. 55878999Smsmith */ 55979375Smsmith if (AcpiGetHandle(NULL, obj->String.Pointer, &cooler) == AE_OK) { 56079375Smsmith if (ACPI_FAILURE(status = acpi_pwr_switch_consumer(cooler, ACPI_STATE_D0))) { 56179375Smsmith device_printf(sc->tz_dev, "failed to activate %s - %s\n", 56280078Smsmith obj->String.Pointer, AcpiFormatException(status)); 56379375Smsmith } 56479375Smsmith } else { 56579375Smsmith device_printf(sc->tz_dev, "couldn't find %s\n", obj->String.Pointer); 56679375Smsmith } 56778915Smsmith break; 56878915Smsmith 56978915Smsmith default: 57082372Smsmith ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to handle unsupported object type %d\n", 57182372Smsmith obj->Type)); 57278915Smsmith break; 57378915Smsmith } 57478915Smsmith return_VOID; 57578915Smsmith} 57678915Smsmith 57778915Smsmith/* 57878915Smsmith * Read/debug-print a parameter, default it to -1. 57978915Smsmith */ 58078915Smsmithstatic void 58178915Smsmithacpi_tz_getparam(struct acpi_tz_softc *sc, char *node, int *data) 58278915Smsmith{ 58378915Smsmith 58478915Smsmith FUNCTION_TRACE(__func__); 58578915Smsmith 58678999Smsmith ACPI_ASSERTLOCK; 58778999Smsmith 58878915Smsmith if (acpi_EvaluateInteger(sc->tz_handle, node, data) != AE_OK) { 58978915Smsmith *data = -1; 59078915Smsmith } else { 59182372Smsmith ACPI_DEBUG_PRINT((ACPI_DB_VALUES, "%s.%s = %d\n", acpi_name(sc->tz_handle), 59282372Smsmith node, *data)); 59378915Smsmith } 59478915Smsmith return_VOID; 59578915Smsmith} 59679283Smsmith 59779283Smsmith/* 59879283Smsmith * Sanity-check a temperature value. Assume that setpoints 59979283Smsmith * should be between 0C and 150C. 60079283Smsmith */ 60179283Smsmithstatic void 60279283Smsmithacpi_tz_sanity(struct acpi_tz_softc *sc, int *val, char *what) 60379283Smsmith{ 60479283Smsmith if ((*val != -1) && ((*val < TZ_ZEROC) || (*val > (TZ_ZEROC + 1500)))) { 60579283Smsmith device_printf(sc->tz_dev, "%s value is absurd, ignored (%d.%dC)\n", 60679283Smsmith what, TZ_KELVTOC(*val)); 60779283Smsmith *val = -1; 60879283Smsmith } 60979283Smsmith} 61079375Smsmith 61179375Smsmith/* 61279375Smsmith * Respond to a sysctl on the active state node. 61379375Smsmith */ 61479375Smsmithstatic int 61579375Smsmithacpi_tz_active_sysctl(SYSCTL_HANDLER_ARGS) 61679375Smsmith{ 61779375Smsmith struct acpi_tz_softc *sc; 61879375Smsmith int active; 61979375Smsmith int error; 62079375Smsmith 62179375Smsmith ACPI_LOCK; 62279375Smsmith 62379375Smsmith sc = (struct acpi_tz_softc *)oidp->oid_arg1; 62479375Smsmith active = sc->tz_active; 62579375Smsmith error = sysctl_handle_int(oidp, &active, 0, req); 62679375Smsmith 62779375Smsmith /* error or no new value */ 62879375Smsmith if ((error != 0) || (req->newptr == NULL)) 62979375Smsmith goto out; 63078915Smsmith 63179375Smsmith /* range check */ 63279375Smsmith if ((active < -1) || (active >= TZ_NUMLEVELS)) { 63379375Smsmith error = EINVAL; 63479375Smsmith goto out; 63579375Smsmith } 63679375Smsmith 63779375Smsmith /* set new preferred level and re-switch */ 63879375Smsmith sc->tz_requested = active; 63979375Smsmith acpi_tz_monitor(sc); 64079375Smsmith 64179375Smsmith out: 64279375Smsmith ACPI_UNLOCK; 64379375Smsmith return(error); 64479375Smsmith} 64579375Smsmith 64678915Smsmith/* 64778915Smsmith * Respond to a Notify event sent to the zone. 64878915Smsmith */ 64978915Smsmithstatic void 65071874Smsmithacpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context) 65171874Smsmith{ 65278915Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)context; 65378915Smsmith 65477432Smsmith FUNCTION_TRACE(__func__); 65570271Stakawata 65678999Smsmith ACPI_ASSERTLOCK; 65778999Smsmith 65878915Smsmith switch(notify) { 65978915Smsmith case TZ_NOTIFY_TEMPERATURE: 66078999Smsmith /* temperature change occurred */ 66178999Smsmith AcpiOsQueueForExecution(OSD_PRIORITY_HIGH, (OSD_EXECUTION_CALLBACK)acpi_tz_monitor, sc); 66278915Smsmith break; 66378915Smsmith case TZ_NOTIFY_DEVICES: 66478915Smsmith case TZ_NOTIFY_LEVELS: 66578999Smsmith /* zone devices/setpoints changed */ 66678999Smsmith AcpiOsQueueForExecution(OSD_PRIORITY_HIGH, (OSD_EXECUTION_CALLBACK)acpi_tz_establish, sc); 66778915Smsmith break; 66878915Smsmith default: 66978915Smsmith device_printf(sc->tz_dev, "unknown Notify event 0x%x\n", notify); 67078915Smsmith break; 67171874Smsmith } 67271874Smsmith return_VOID; 67371874Smsmith} 67470271Stakawata 67578915Smsmith/* 67678915Smsmith * Poll the thermal zone. 67778915Smsmith */ 67878915Smsmithstatic void 67978915Smsmithacpi_tz_timeout(void *arg) 68078915Smsmith{ 68178915Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg; 68278915Smsmith 68379375Smsmith /* do we need to get the power profile settings? */ 68479375Smsmith if (sc->tz_flags & TZ_FLAG_GETPROFILE) { 68579375Smsmith acpi_tz_powerprofile(arg); 68679375Smsmith sc->tz_flags &= ~TZ_FLAG_GETPROFILE; 68779375Smsmith } 68879375Smsmith 68978999Smsmith ACPI_LOCK; 69078999Smsmith 69178915Smsmith /* check temperature, take action */ 69278999Smsmith AcpiOsQueueForExecution(OSD_PRIORITY_HIGH, (OSD_EXECUTION_CALLBACK)acpi_tz_monitor, sc); 69378915Smsmith 69478915Smsmith /* XXX passive cooling actions? */ 69578915Smsmith 69678915Smsmith /* re-register ourself */ 69778915Smsmith sc->tz_timeout = timeout(acpi_tz_timeout, sc, TZ_POLLRATE); 69878999Smsmith 69978999Smsmith ACPI_UNLOCK; 70078915Smsmith} 70179375Smsmith 70279375Smsmith/* 70379375Smsmith * System power profile may have changed; fetch and notify the 70479375Smsmith * thermal zone accordingly. 70579375Smsmith * 70679375Smsmith * Since this can be called from an arbitrary eventhandler, it needs 70779375Smsmith * to get the ACPI lock itself. 70879375Smsmith */ 70979375Smsmithstatic void 71079375Smsmithacpi_tz_powerprofile(void *arg) 71179375Smsmith{ 71279375Smsmith ACPI_OBJECT_LIST args; 71379375Smsmith ACPI_OBJECT obj; 71479375Smsmith ACPI_STATUS status; 71579375Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg; 71679375Smsmith 71779375Smsmith ACPI_LOCK; 71879375Smsmith 71979375Smsmith /* check that we haven't decided there's no _SCP method */ 72079375Smsmith if (!(sc->tz_flags & TZ_FLAG_NO_SCP)) { 72179375Smsmith 72279375Smsmith /* call _SCP to set the new profile */ 72379375Smsmith obj.Type = ACPI_TYPE_INTEGER; 72479375Smsmith obj.Integer.Value = (powerprofile_get_state() == POWERPROFILE_PERFORMANCE) ? 0 : 1; 72579375Smsmith args.Count = 1; 72679375Smsmith args.Pointer = &obj; 72779375Smsmith if (ACPI_FAILURE(status = AcpiEvaluateObject(sc->tz_handle, "_SCP", &args, NULL))) { 72879385Smsmith if (status != AE_NOT_FOUND) 72979385Smsmith device_printf(sc->tz_dev, "can't evaluate %s._SCP - %s\n", acpi_name(sc->tz_handle), 73080078Smsmith AcpiFormatException(status)); 73179375Smsmith sc->tz_flags |= TZ_FLAG_NO_SCP; 73279375Smsmith } else { 73379375Smsmith /* we have to re-evaluate the entire zone now */ 73479375Smsmith AcpiOsQueueForExecution(OSD_PRIORITY_HIGH, (OSD_EXECUTION_CALLBACK)acpi_tz_establish, sc); 73579375Smsmith } 73679375Smsmith } 73779375Smsmith ACPI_UNLOCK; 73879375Smsmith} 73979375Smsmith 740