acpi_thermal.c revision 79375
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 79375 2001-07-07 01:49:15Z msmith $ 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 5078915Smsmith#define TZ_NOTIFY_TEMPERATURE 0x80 5178915Smsmith#define TZ_NOTIFY_DEVICES 0x81 5278915Smsmith#define TZ_NOTIFY_LEVELS 0x82 5378915Smsmith 5478915Smsmith#define TZ_POLLRATE (hz * 10) /* every ten seconds */ 5578915Smsmith 5678915Smsmith#define TZ_NUMLEVELS 10 /* defined by ACPI spec */ 5779375Smsmithstruct acpi_tz_zone { 5878915Smsmith int ac[TZ_NUMLEVELS]; 5978915Smsmith ACPI_BUFFER al[TZ_NUMLEVELS]; 6078915Smsmith int crt; 6178915Smsmith int hot; 6278915Smsmith ACPI_BUFFER psl; 6378915Smsmith int psv; 6478915Smsmith int tc1; 6578915Smsmith int tc2; 6678915Smsmith int tsp; 6778915Smsmith int tzp; 6878915Smsmith}; 6978915Smsmith 7078915Smsmith 7167761Smsmithstruct acpi_tz_softc { 7279375Smsmith device_t tz_dev; /* device handle */ 7379375Smsmith ACPI_HANDLE tz_handle; /* thermal zone handle */ 7479375Smsmith struct callout_handle tz_timeout; /* poll routine handle */ 7579375Smsmith int tz_temperature; /* current temperature */ 7679375Smsmith int tz_active; /* current active cooling */ 7779375Smsmith#define TZ_ACTIVE_NONE -1 7879375Smsmith int tz_requested; /* user-requested minimum active cooling */ 7979375Smsmith int tz_thflags; /* current temperature-related flags */ 8079375Smsmith#define TZ_THFLAG_NONE 0 8179375Smsmith#define TZ_THFLAG_PSV (1<<0) 8279375Smsmith#define TZ_THFLAG_HOT (1<<2) 8379375Smsmith#define TZ_THFLAG_CRT (1<<3) 8479283Smsmith int tz_flags; 8579375Smsmith#define TZ_FLAG_NO_SCP (1<<0) /* no _SCP method */ 8679375Smsmith#define TZ_FLAG_GETPROFILE (1<<1) /* fetch powerprofile in timeout */ 8779283Smsmith 8879375Smsmith struct sysctl_ctx_list tz_sysctl_ctx; /* sysctl tree */ 8979283Smsmith struct sysctl_oid *tz_sysctl_tree; 9078915Smsmith 9179375Smsmith struct acpi_tz_zone tz_zone; /* thermal zone parameters */ 9267761Smsmith}; 9367761Smsmith 9467761Smsmithstatic int acpi_tz_probe(device_t dev); 9567761Smsmithstatic int acpi_tz_attach(device_t dev); 9678915Smsmithstatic int acpi_tz_establish(struct acpi_tz_softc *sc); 9778999Smsmithstatic void acpi_tz_monitor(struct acpi_tz_softc *sc); 9878915Smsmithstatic void acpi_tz_all_off(struct acpi_tz_softc *sc); 9978915Smsmithstatic void acpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg); 10078915Smsmithstatic void acpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg); 10178915Smsmithstatic void acpi_tz_getparam(struct acpi_tz_softc *sc, char *node, int *data); 10279283Smsmithstatic void acpi_tz_sanity(struct acpi_tz_softc *sc, int *val, char *what); 10379375Smsmithstatic int acpi_tz_active_sysctl(SYSCTL_HANDLER_ARGS); 10471874Smsmithstatic void acpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context); 10578915Smsmithstatic void acpi_tz_timeout(void *arg); 10679375Smsmithstatic void acpi_tz_powerprofile(void *arg); 10771874Smsmith 10867761Smsmithstatic device_method_t acpi_tz_methods[] = { 10967761Smsmith /* Device interface */ 11067761Smsmith DEVMETHOD(device_probe, acpi_tz_probe), 11167761Smsmith DEVMETHOD(device_attach, acpi_tz_attach), 11267761Smsmith 11367761Smsmith {0, 0} 11467761Smsmith}; 11567761Smsmith 11667761Smsmithstatic driver_t acpi_tz_driver = { 11767761Smsmith "acpi_tz", 11867761Smsmith acpi_tz_methods, 11967761Smsmith sizeof(struct acpi_tz_softc), 12067761Smsmith}; 12167761Smsmith 12267761Smsmithdevclass_t acpi_tz_devclass; 12367761SmsmithDRIVER_MODULE(acpi_tz, acpi, acpi_tz_driver, acpi_tz_devclass, 0, 0); 12467761Smsmith 12579283Smsmithstatic struct sysctl_ctx_list acpi_tz_sysctl_ctx; 12679283Smsmithstatic struct sysctl_oid *acpi_tz_sysctl_tree; 12779283Smsmith 12878915Smsmith/* 12978915Smsmith * Match an ACPI thermal zone. 13078915Smsmith */ 13167761Smsmithstatic int 13267761Smsmithacpi_tz_probe(device_t dev) 13367761Smsmith{ 13478999Smsmith int result; 13578999Smsmith 13678999Smsmith ACPI_LOCK; 13778999Smsmith 13878915Smsmith /* no FUNCTION_TRACE - too noisy */ 13969744Smsmith 14069744Smsmith if ((acpi_get_type(dev) == ACPI_TYPE_THERMAL) && 14169744Smsmith !acpi_disabled("thermal")) { 14267761Smsmith device_set_desc(dev, "thermal zone"); 14378999Smsmith result = -10; 14478999Smsmith } else { 14578999Smsmith result = ENXIO; 14667761Smsmith } 14778999Smsmith ACPI_UNLOCK; 14878999Smsmith return(result); 14967761Smsmith} 15067761Smsmith 15178915Smsmith/* 15278915Smsmith * Attach to an ACPI thermal zone. 15378915Smsmith */ 15467761Smsmithstatic int 15567761Smsmithacpi_tz_attach(device_t dev) 15667761Smsmith{ 15767761Smsmith struct acpi_tz_softc *sc; 15879283Smsmith struct acpi_softc *acpi_sc; 15978915Smsmith int error; 16079283Smsmith char oidname[8]; 16179283Smsmith int i; 16267761Smsmith 16377432Smsmith FUNCTION_TRACE(__func__); 16469744Smsmith 16578999Smsmith ACPI_LOCK; 16678999Smsmith 16767761Smsmith sc = device_get_softc(dev); 16867761Smsmith sc->tz_dev = dev; 16967761Smsmith sc->tz_handle = acpi_get_handle(dev); 17079375Smsmith sc->tz_requested = TZ_ACTIVE_NONE; 17167761Smsmith 17278915Smsmith /* 17378915Smsmith * Parse the current state of the thermal zone and build control 17478915Smsmith * structures. 17578915Smsmith */ 17678915Smsmith if ((error = acpi_tz_establish(sc)) != 0) 17778999Smsmith goto out; 17878915Smsmith 17978915Smsmith /* 18078915Smsmith * Register for any Notify events sent to this zone. 18178915Smsmith */ 18271874Smsmith AcpiInstallNotifyHandler(sc->tz_handle, ACPI_DEVICE_NOTIFY, 18378999Smsmith acpi_tz_notify_handler, sc); 18470271Stakawata 18571874Smsmith /* 18679283Smsmith * Create our sysctl nodes. 18779283Smsmith * 18879283Smsmith * XXX we need a mechanism for adding nodes under ACPI. 18979283Smsmith */ 19079283Smsmith if (device_get_unit(dev) == 0) { 19179283Smsmith acpi_sc = acpi_device_get_parent_softc(dev); 19279283Smsmith sysctl_ctx_init(&acpi_tz_sysctl_ctx); 19379283Smsmith acpi_tz_sysctl_tree = SYSCTL_ADD_NODE(&acpi_tz_sysctl_ctx, 19479283Smsmith SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), 19579283Smsmith OID_AUTO, "thermal", CTLFLAG_RD, 0, ""); 19679283Smsmith } 19779283Smsmith sysctl_ctx_init(&sc->tz_sysctl_ctx); 19879283Smsmith sprintf(oidname, "tz%d", device_get_unit(dev)); 19979283Smsmith sc->tz_sysctl_tree = SYSCTL_ADD_NODE(&sc->tz_sysctl_ctx, 20079283Smsmith SYSCTL_CHILDREN(acpi_tz_sysctl_tree), OID_AUTO, 20179283Smsmith oidname, CTLFLAG_RD, 0, ""); 20279283Smsmith SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 20379283Smsmith OID_AUTO, "temperature", CTLFLAG_RD, 20479283Smsmith &sc->tz_temperature, 0, "current thermal zone temperature"); 20579375Smsmith SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 20679375Smsmith OID_AUTO, "active", CTLTYPE_INT | CTLFLAG_RW, 20779375Smsmith sc, 0, acpi_tz_active_sysctl, "I", ""); 20879375Smsmith 20979283Smsmith SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 21079375Smsmith OID_AUTO, "thermal_flags", CTLFLAG_RD, 21179375Smsmith &sc->tz_thflags, 0, "thermal zone flags"); 21279283Smsmith SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 21379283Smsmith OID_AUTO, "_PSV", CTLFLAG_RD, 21479375Smsmith &sc->tz_zone.psv, 0, ""); 21579283Smsmith SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 21679283Smsmith OID_AUTO, "_HOT", CTLFLAG_RD, 21779375Smsmith &sc->tz_zone.hot, 0, ""); 21879283Smsmith SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 21979283Smsmith OID_AUTO, "_CRT", CTLFLAG_RD, 22079375Smsmith &sc->tz_zone.crt, 0, ""); 22179283Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) { 22279283Smsmith sprintf(oidname, "_AC%d", i); 22379283Smsmith SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 22479283Smsmith OID_AUTO, oidname, CTLFLAG_RD, 22579375Smsmith &sc->tz_zone.ac[i], 0, ""); 22679283Smsmith } 22779283Smsmith 22879283Smsmith /* 22979375Smsmith * Register our power profile event handler, and flag it for a manual 23079375Smsmith * invocation by our timeout. We defer it like this so that the rest 23179375Smsmith * of the subsystem has time to come up. 23279375Smsmith */ 23379375Smsmith EVENTHANDLER_REGISTER(powerprofile_change, acpi_tz_powerprofile, sc, 0); 23479375Smsmith sc->tz_flags |= TZ_FLAG_GETPROFILE; 23579375Smsmith 23679375Smsmith /* 23771874Smsmith * Don't bother evaluating/printing the temperature at this point; 23871874Smsmith * on many systems it'll be bogus until the EC is running. 23971874Smsmith */ 24078999Smsmith 24178999Smsmith out: 24278999Smsmith ACPI_UNLOCK; 24379375Smsmith 24479375Smsmith /* 24579375Smsmith * Start the timeout routine, with enough delay for the rest of the 24679375Smsmith * subsystem to come up. 24779375Smsmith */ 24879375Smsmith sc->tz_timeout = timeout(acpi_tz_timeout, sc, TZ_POLLRATE); 24979375Smsmith 25078999Smsmith return_VALUE(error); 25167761Smsmith} 25270271Stakawata 25378915Smsmith/* 25478915Smsmith * Parse the current state of this thermal zone and set up to use it. 25578915Smsmith * 25678915Smsmith * Note that we may have previous state, which will have to be discarded. 25778915Smsmith */ 25878915Smsmithstatic int 25978915Smsmithacpi_tz_establish(struct acpi_tz_softc *sc) 26078915Smsmith{ 26178915Smsmith ACPI_OBJECT *obj; 26278915Smsmith int i; 26378915Smsmith char nbuf[8]; 26478915Smsmith 26578915Smsmith FUNCTION_TRACE(__func__); 26678915Smsmith 26778999Smsmith ACPI_ASSERTLOCK; 26878999Smsmith 26978915Smsmith /* 27078915Smsmith * Power everything off and erase any existing state. 27178915Smsmith */ 27278915Smsmith acpi_tz_all_off(sc); 27378915Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) 27479375Smsmith if (sc->tz_zone.al[i].Pointer != NULL) 27579375Smsmith AcpiOsFree(sc->tz_zone.al[i].Pointer); 27679375Smsmith if (sc->tz_zone.psl.Pointer != NULL) 27779375Smsmith AcpiOsFree(sc->tz_zone.psl.Pointer); 27879375Smsmith bzero(&sc->tz_zone, sizeof(sc->tz_zone)); 27978915Smsmith 28078915Smsmith /* 28178915Smsmith * Evaluate thermal zone parameters. 28278915Smsmith */ 28378915Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) { 28478915Smsmith sprintf(nbuf, "_AC%d", i); 28579375Smsmith acpi_tz_getparam(sc, nbuf, &sc->tz_zone.ac[i]); 28678915Smsmith sprintf(nbuf, "_AL%d", i); 28779375Smsmith acpi_EvaluateIntoBuffer(sc->tz_handle, nbuf, NULL, &sc->tz_zone.al[i]); 28879375Smsmith obj = (ACPI_OBJECT *)sc->tz_zone.al[i].Pointer; 28978915Smsmith if (obj != NULL) { 29078915Smsmith /* should be a package containing a list of power objects */ 29178915Smsmith if (obj->Type != ACPI_TYPE_PACKAGE) { 29278915Smsmith device_printf(sc->tz_dev, "%s has unknown object type %d, rejecting\n", 29378915Smsmith nbuf, obj->Type); 29478915Smsmith return_VALUE(ENXIO); 29578915Smsmith } 29678915Smsmith } 29778915Smsmith } 29879375Smsmith acpi_tz_getparam(sc, "_CRT", &sc->tz_zone.crt); 29979375Smsmith acpi_tz_getparam(sc, "_HOT", &sc->tz_zone.hot); 30079375Smsmith acpi_EvaluateIntoBuffer(sc->tz_handle, "_PSL", NULL, &sc->tz_zone.psl); 30179375Smsmith acpi_tz_getparam(sc, "_PSV", &sc->tz_zone.psv); 30279375Smsmith acpi_tz_getparam(sc, "_TC1", &sc->tz_zone.tc1); 30379375Smsmith acpi_tz_getparam(sc, "_TC2", &sc->tz_zone.tc2); 30479375Smsmith acpi_tz_getparam(sc, "_TSP", &sc->tz_zone.tsp); 30579375Smsmith acpi_tz_getparam(sc, "_TZP", &sc->tz_zone.tzp); 30678915Smsmith 30778915Smsmith /* 30879283Smsmith * Sanity-check the values we've been given. 30979283Smsmith * 31079283Smsmith * XXX what do we do about systems that give us the same value for 31179283Smsmith * more than one of these setpoints? 31279283Smsmith */ 31379375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.crt, "_CRT"); 31479375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.hot, "_HOT"); 31579375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.psv, "_PSV"); 31679283Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) 31779375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.ac[i], "_ACx"); 31879283Smsmith 31979283Smsmith /* 32078915Smsmith * Power off everything that we've just been given. 32178915Smsmith */ 32278915Smsmith acpi_tz_all_off(sc); 32378915Smsmith 32478915Smsmith return_VALUE(0); 32578915Smsmith} 32678915Smsmith 32778915Smsmith/* 32878915Smsmith * Evaluate the condition of a thermal zone, take appropriate actions. 32978915Smsmith */ 33071874Smsmithstatic void 33178915Smsmithacpi_tz_monitor(struct acpi_tz_softc *sc) 33271874Smsmith{ 33379283Smsmith int temp; 33478915Smsmith int i; 33579283Smsmith int newactive, newflags; 33670271Stakawata 33777432Smsmith FUNCTION_TRACE(__func__); 33870271Stakawata 33978999Smsmith ACPI_ASSERTLOCK; 34078999Smsmith 34178915Smsmith /* 34278915Smsmith * Get the current temperature. 34378915Smsmith */ 34478915Smsmith if ((acpi_EvaluateInteger(sc->tz_handle, "_TMP", &temp)) != AE_OK) { 34578915Smsmith device_printf(sc->tz_dev, "error fetching current temperature\n"); 34678915Smsmith /* XXX disable zone? go to max cooling? */ 34771874Smsmith return_VOID; 34871874Smsmith } 34978999Smsmith DEBUG_PRINT(TRACE_VALUES, ("got %d.%dC\n", TZ_KELVTOC(temp))); 35079283Smsmith sc->tz_temperature = temp; 35178915Smsmith 35278915Smsmith /* 35378915Smsmith * Work out what we ought to be doing right now. 35479283Smsmith * 35579283Smsmith * Note that the _ACx levels sort from hot to cold. 35678915Smsmith */ 35779283Smsmith newactive = TZ_ACTIVE_NONE; 35879375Smsmith for (i = TZ_NUMLEVELS - 1; i >= 0; i--) { 35979375Smsmith if ((sc->tz_zone.ac[i] != -1) && (temp >= sc->tz_zone.ac[i])) { 36079375Smsmith device_printf(sc->tz_dev, "_AC%d: temperature %d > setpoint %d\n", 36179375Smsmith i, temp, sc->tz_zone.ac[i]); 36279283Smsmith newactive = i; 36379375Smsmith } 36479375Smsmith } 36579283Smsmith 36679375Smsmith /* handle user override of active mode */ 36779375Smsmith if (sc->tz_requested > newactive) 36879375Smsmith newactive = sc->tz_requested; 36978915Smsmith 37079375Smsmith /* update temperature-related flags */ 37179375Smsmith newflags = TZ_THFLAG_NONE; 37279375Smsmith if ((sc->tz_zone.psv != -1) && (temp >= sc->tz_zone.psv)) 37379375Smsmith newflags |= TZ_THFLAG_PSV; 37479375Smsmith if ((sc->tz_zone.hot != -1) && (temp >= sc->tz_zone.hot)) 37579375Smsmith newflags |= TZ_THFLAG_HOT; 37679375Smsmith if ((sc->tz_zone.crt != -1) && (temp >= sc->tz_zone.crt)) 37779375Smsmith newflags |= TZ_THFLAG_CRT; 37879375Smsmith 37978915Smsmith /* 38079283Smsmith * If the active cooling state has changed, we have to switch things. 38178915Smsmith */ 38279283Smsmith if (newactive != sc->tz_active) { 38378915Smsmith 38479283Smsmith /* turn off the cooling devices that are on, if any are */ 38579283Smsmith if (sc->tz_active != TZ_ACTIVE_NONE) 38679375Smsmith acpi_ForeachPackageObject((ACPI_OBJECT *)sc->tz_zone.al[sc->tz_active].Pointer, 38779283Smsmith acpi_tz_switch_cooler_off, sc); 38878915Smsmith 38979283Smsmith /* turn on cooling devices that are required, if any are */ 39079283Smsmith if (newactive != TZ_ACTIVE_NONE) 39179375Smsmith acpi_ForeachPackageObject((ACPI_OBJECT *)sc->tz_zone.al[newactive].Pointer, 39279283Smsmith acpi_tz_switch_cooler_on, sc); 39379375Smsmith device_printf(sc->tz_dev, "switched from _AC%d to _AC%d\n", sc->tz_active, newactive); 39479283Smsmith sc->tz_active = newactive; 39579283Smsmith } 39678915Smsmith 39778915Smsmith /* 39879283Smsmith * XXX (de)activate any passive cooling that may be required. 39978915Smsmith */ 40078915Smsmith 40178915Smsmith /* 40279283Smsmith * If we have just become _HOT or _CRT, warn the user. 40379283Smsmith * 40479283Smsmith * We should actually shut down at this point, but it's not clear 40579283Smsmith * that some systems don't actually map _CRT to the same value as _AC0. 40678915Smsmith */ 40779375Smsmith if ((newflags & (TZ_THFLAG_HOT | TZ_THFLAG_CRT)) && 40879375Smsmith !(sc->tz_thflags & (TZ_THFLAG_HOT | TZ_THFLAG_CRT))) { 40979283Smsmith device_printf(sc->tz_dev, "WARNING - current temperature (%d.%dC) exceeds system limits\n", 41079283Smsmith TZ_KELVTOC(sc->tz_temperature), sc->tz_temperature); 41179283Smsmith /* shutdown_nice(RB_POWEROFF);*/ 41278915Smsmith } 41379375Smsmith sc->tz_thflags = newflags; 41478915Smsmith 41571874Smsmith return_VOID; 41671874Smsmith} 41770271Stakawata 41878915Smsmith/* 41978915Smsmith * Turn off all the cooling devices. 42078915Smsmith */ 42171874Smsmithstatic void 42278915Smsmithacpi_tz_all_off(struct acpi_tz_softc *sc) 42378915Smsmith{ 42478915Smsmith int i; 42578915Smsmith 42678915Smsmith FUNCTION_TRACE(__func__); 42778999Smsmith 42878999Smsmith ACPI_ASSERTLOCK; 42978915Smsmith 43078915Smsmith /* 43179375Smsmith * Scan all the _ALx objects, and turn them all off. 43278915Smsmith */ 43378915Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) { 43479375Smsmith if (sc->tz_zone.al[i].Pointer == NULL) 43578915Smsmith continue; 43679375Smsmith acpi_ForeachPackageObject((ACPI_OBJECT *)sc->tz_zone.al[i].Pointer, 43778915Smsmith acpi_tz_switch_cooler_off, sc); 43878915Smsmith } 43978915Smsmith 44078915Smsmith /* 44178915Smsmith * XXX revert any passive-cooling options. 44278915Smsmith */ 44378915Smsmith 44479283Smsmith sc->tz_active = TZ_ACTIVE_NONE; 44579375Smsmith sc->tz_thflags = TZ_THFLAG_NONE; 44678915Smsmith return_VOID; 44778915Smsmith} 44878915Smsmith 44978915Smsmith/* 45078915Smsmith * Given an object, verify that it's a reference to a device of some sort, 45178915Smsmith * and try to switch it off. 45278915Smsmith */ 45378915Smsmithstatic void 45478915Smsmithacpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg) 45578915Smsmith{ 45679375Smsmith ACPI_HANDLE cooler; 45778915Smsmith 45878915Smsmith FUNCTION_TRACE(__func__); 45978915Smsmith 46078999Smsmith ACPI_ASSERTLOCK; 46178999Smsmith 46278915Smsmith switch(obj->Type) { 46378915Smsmith case ACPI_TYPE_STRING: 46478915Smsmith DEBUG_PRINT(TRACE_OBJECTS, ("called to turn %s off\n", obj->String.Pointer)); 46578915Smsmith 46678915Smsmith /* 46778915Smsmith * Find the handle for the device and turn it off. 46878915Smsmith * The String object here seems to contain a fully-qualified path, so we 46978915Smsmith * don't have to search for it in our parents. 47078915Smsmith * 47178915Smsmith * XXX This may not always be the case. 47278915Smsmith */ 47379375Smsmith if (AcpiGetHandle(NULL, obj->String.Pointer, &cooler) == AE_OK) 47478915Smsmith acpi_pwr_switch_consumer(cooler, ACPI_STATE_D3); 47578915Smsmith break; 47678915Smsmith 47778915Smsmith default: 47878915Smsmith DEBUG_PRINT(TRACE_OBJECTS, ("called to handle unsupported object type %d\n", 47978915Smsmith obj->Type)); 48078915Smsmith break; 48178915Smsmith } 48279375Smsmith return_VOID; 48378915Smsmith} 48478915Smsmith 48578915Smsmith/* 48678915Smsmith * Given an object, verify that it's a reference to a device of some sort, 48778915Smsmith * and try to switch it on. 48878915Smsmith * 48978915Smsmith * XXX replication of off/on function code is bad, mmmkay? 49078915Smsmith */ 49178915Smsmithstatic void 49278915Smsmithacpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg) 49378915Smsmith{ 49478915Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg; 49578999Smsmith ACPI_HANDLE cooler; 49679375Smsmith ACPI_STATUS status; 49779375Smsmith 49878915Smsmith FUNCTION_TRACE(__func__); 49978915Smsmith 50078999Smsmith ACPI_ASSERTLOCK; 50178999Smsmith 50278915Smsmith switch(obj->Type) { 50378915Smsmith case ACPI_TYPE_STRING: 50479375Smsmith DEBUG_PRINT(TRACE_OBJECTS, ("called to turn %s on\n", obj->String.Pointer)); 50578915Smsmith 50678999Smsmith /* 50778999Smsmith * Find the handle for the device and turn it off. 50878999Smsmith * The String object here seems to contain a fully-qualified path, so we 50978999Smsmith * don't have to search for it in our parents. 51078999Smsmith * 51178999Smsmith * XXX This may not always be the case. 51278999Smsmith */ 51379375Smsmith if (AcpiGetHandle(NULL, obj->String.Pointer, &cooler) == AE_OK) { 51479375Smsmith if (ACPI_FAILURE(status = acpi_pwr_switch_consumer(cooler, ACPI_STATE_D0))) { 51579375Smsmith device_printf(sc->tz_dev, "failed to activate %s - %s\n", 51679375Smsmith obj->String.Pointer, acpi_strerror(status)); 51779375Smsmith } 51879375Smsmith } else { 51979375Smsmith device_printf(sc->tz_dev, "couldn't find %s\n", obj->String.Pointer); 52079375Smsmith } 52178915Smsmith break; 52278915Smsmith 52378915Smsmith default: 52478915Smsmith DEBUG_PRINT(TRACE_OBJECTS, ("called to handle unsupported object type %d\n", 52578915Smsmith obj->Type)); 52678915Smsmith break; 52778915Smsmith } 52878915Smsmith return_VOID; 52978915Smsmith} 53078915Smsmith 53178915Smsmith/* 53278915Smsmith * Read/debug-print a parameter, default it to -1. 53378915Smsmith */ 53478915Smsmithstatic void 53578915Smsmithacpi_tz_getparam(struct acpi_tz_softc *sc, char *node, int *data) 53678915Smsmith{ 53778915Smsmith 53878915Smsmith FUNCTION_TRACE(__func__); 53978915Smsmith 54078999Smsmith ACPI_ASSERTLOCK; 54178999Smsmith 54278915Smsmith if (acpi_EvaluateInteger(sc->tz_handle, node, data) != AE_OK) { 54378915Smsmith *data = -1; 54478915Smsmith } else { 54578915Smsmith DEBUG_PRINT(TRACE_VALUES, ("%s.%s = %d\n", acpi_name(sc->tz_handle), 54678915Smsmith node, *data)); 54778915Smsmith } 54878915Smsmith return_VOID; 54978915Smsmith} 55079283Smsmith 55179283Smsmith/* 55279283Smsmith * Sanity-check a temperature value. Assume that setpoints 55379283Smsmith * should be between 0C and 150C. 55479283Smsmith */ 55579283Smsmithstatic void 55679283Smsmithacpi_tz_sanity(struct acpi_tz_softc *sc, int *val, char *what) 55779283Smsmith{ 55879283Smsmith if ((*val != -1) && ((*val < TZ_ZEROC) || (*val > (TZ_ZEROC + 1500)))) { 55979283Smsmith device_printf(sc->tz_dev, "%s value is absurd, ignored (%d.%dC)\n", 56079283Smsmith what, TZ_KELVTOC(*val)); 56179283Smsmith *val = -1; 56279283Smsmith } 56379283Smsmith} 56479375Smsmith 56579375Smsmith/* 56679375Smsmith * Respond to a sysctl on the active state node. 56779375Smsmith */ 56879375Smsmithstatic int 56979375Smsmithacpi_tz_active_sysctl(SYSCTL_HANDLER_ARGS) 57079375Smsmith{ 57179375Smsmith struct acpi_tz_softc *sc; 57279375Smsmith int active; 57379375Smsmith int error; 57479375Smsmith 57579375Smsmith ACPI_LOCK; 57679375Smsmith 57779375Smsmith sc = (struct acpi_tz_softc *)oidp->oid_arg1; 57879375Smsmith active = sc->tz_active; 57979375Smsmith error = sysctl_handle_int(oidp, &active, 0, req); 58079375Smsmith 58179375Smsmith /* error or no new value */ 58279375Smsmith if ((error != 0) || (req->newptr == NULL)) 58379375Smsmith goto out; 58478915Smsmith 58579375Smsmith /* range check */ 58679375Smsmith if ((active < -1) || (active >= TZ_NUMLEVELS)) { 58779375Smsmith error = EINVAL; 58879375Smsmith goto out; 58979375Smsmith } 59079375Smsmith 59179375Smsmith /* set new preferred level and re-switch */ 59279375Smsmith sc->tz_requested = active; 59379375Smsmith acpi_tz_monitor(sc); 59479375Smsmith 59579375Smsmith out: 59679375Smsmith ACPI_UNLOCK; 59779375Smsmith return(error); 59879375Smsmith} 59979375Smsmith 60078915Smsmith/* 60178915Smsmith * Respond to a Notify event sent to the zone. 60278915Smsmith */ 60378915Smsmithstatic void 60471874Smsmithacpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context) 60571874Smsmith{ 60678915Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)context; 60778915Smsmith 60877432Smsmith FUNCTION_TRACE(__func__); 60970271Stakawata 61078999Smsmith ACPI_ASSERTLOCK; 61178999Smsmith 61278915Smsmith switch(notify) { 61378915Smsmith case TZ_NOTIFY_TEMPERATURE: 61478999Smsmith /* temperature change occurred */ 61579375Smsmith device_printf(sc->tz_dev, "notified of temperature reaching setpoint\n"); 61678999Smsmith AcpiOsQueueForExecution(OSD_PRIORITY_HIGH, (OSD_EXECUTION_CALLBACK)acpi_tz_monitor, sc); 61778915Smsmith break; 61878915Smsmith case TZ_NOTIFY_DEVICES: 61978915Smsmith case TZ_NOTIFY_LEVELS: 62078999Smsmith /* zone devices/setpoints changed */ 62179375Smsmith device_printf(sc->tz_dev, "notified of zone configuration change\n"); 62278999Smsmith AcpiOsQueueForExecution(OSD_PRIORITY_HIGH, (OSD_EXECUTION_CALLBACK)acpi_tz_establish, sc); 62378915Smsmith break; 62478915Smsmith default: 62578915Smsmith device_printf(sc->tz_dev, "unknown Notify event 0x%x\n", notify); 62678915Smsmith break; 62771874Smsmith } 62871874Smsmith return_VOID; 62971874Smsmith} 63070271Stakawata 63178915Smsmith/* 63278915Smsmith * Poll the thermal zone. 63378915Smsmith */ 63478915Smsmithstatic void 63578915Smsmithacpi_tz_timeout(void *arg) 63678915Smsmith{ 63778915Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg; 63878915Smsmith 63979375Smsmith /* do we need to get the power profile settings? */ 64079375Smsmith if (sc->tz_flags & TZ_FLAG_GETPROFILE) { 64179375Smsmith acpi_tz_powerprofile(arg); 64279375Smsmith sc->tz_flags &= ~TZ_FLAG_GETPROFILE; 64379375Smsmith } 64479375Smsmith 64578999Smsmith ACPI_LOCK; 64678999Smsmith 64778915Smsmith /* check temperature, take action */ 64878999Smsmith AcpiOsQueueForExecution(OSD_PRIORITY_HIGH, (OSD_EXECUTION_CALLBACK)acpi_tz_monitor, sc); 64978915Smsmith 65078915Smsmith /* XXX passive cooling actions? */ 65178915Smsmith 65278915Smsmith /* re-register ourself */ 65378915Smsmith sc->tz_timeout = timeout(acpi_tz_timeout, sc, TZ_POLLRATE); 65478999Smsmith 65578999Smsmith ACPI_UNLOCK; 65678915Smsmith} 65779375Smsmith 65879375Smsmith/* 65979375Smsmith * System power profile may have changed; fetch and notify the 66079375Smsmith * thermal zone accordingly. 66179375Smsmith * 66279375Smsmith * Since this can be called from an arbitrary eventhandler, it needs 66379375Smsmith * to get the ACPI lock itself. 66479375Smsmith */ 66579375Smsmithstatic void 66679375Smsmithacpi_tz_powerprofile(void *arg) 66779375Smsmith{ 66879375Smsmith ACPI_OBJECT_LIST args; 66979375Smsmith ACPI_OBJECT obj; 67079375Smsmith ACPI_STATUS status; 67179375Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg; 67279375Smsmith 67379375Smsmith ACPI_LOCK; 67479375Smsmith 67579375Smsmith /* check that we haven't decided there's no _SCP method */ 67679375Smsmith if (!(sc->tz_flags & TZ_FLAG_NO_SCP)) { 67779375Smsmith 67879375Smsmith /* call _SCP to set the new profile */ 67979375Smsmith obj.Type = ACPI_TYPE_INTEGER; 68079375Smsmith obj.Integer.Value = (powerprofile_get_state() == POWERPROFILE_PERFORMANCE) ? 0 : 1; 68179375Smsmith args.Count = 1; 68279375Smsmith args.Pointer = &obj; 68379375Smsmith if (ACPI_FAILURE(status = AcpiEvaluateObject(sc->tz_handle, "_SCP", &args, NULL))) { 68479375Smsmith device_printf(sc->tz_dev, "can't evaluate %s._SCP - %s\n", acpi_name(sc->tz_handle), 68579375Smsmith acpi_strerror(status)); /* XXX silence this at some point */ 68679375Smsmith sc->tz_flags |= TZ_FLAG_NO_SCP; 68779375Smsmith } else { 68879375Smsmith /* we have to re-evaluate the entire zone now */ 68979375Smsmith AcpiOsQueueForExecution(OSD_PRIORITY_HIGH, (OSD_EXECUTION_CALLBACK)acpi_tz_establish, sc); 69079375Smsmith } 69179375Smsmith } 69279375Smsmith ACPI_UNLOCK; 69379375Smsmith} 69479375Smsmith 695