acpi_thermal.c revision 220871
167761Smsmith/*- 278915Smsmith * Copyright (c) 2000, 2001 Michael Smith 367761Smsmith * Copyright (c) 2000 BSDi 467761Smsmith * All rights reserved. 567761Smsmith * 667761Smsmith * Redistribution and use in source and binary forms, with or without 767761Smsmith * modification, are permitted provided that the following conditions 867761Smsmith * are met: 967761Smsmith * 1. Redistributions of source code must retain the above copyright 1067761Smsmith * notice, this list of conditions and the following disclaimer. 1167761Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1267761Smsmith * notice, this list of conditions and the following disclaimer in the 1367761Smsmith * documentation and/or other materials provided with the distribution. 1467761Smsmith * 1567761Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1667761Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1767761Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1867761Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1967761Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2067761Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2167761Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2267761Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2367761Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2467761Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2567761Smsmith * SUCH DAMAGE. 2667761Smsmith */ 2767761Smsmith 28119418Sobrien#include <sys/cdefs.h> 29119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/acpica/acpi_thermal.c 220871 2011-04-19 20:44:43Z mdf $"); 30119418Sobrien 3167761Smsmith#include "opt_acpi.h" 3267761Smsmith#include <sys/param.h> 3367761Smsmith#include <sys/kernel.h> 34133624Snjl#include <sys/bus.h> 35148138Sume#include <sys/cpu.h> 3691126Smsmith#include <sys/kthread.h> 37133624Snjl#include <sys/malloc.h> 38129879Sphk#include <sys/module.h> 3967761Smsmith#include <sys/bus.h> 4091126Smsmith#include <sys/proc.h> 41128991Snjl#include <sys/reboot.h> 4279283Smsmith#include <sys/sysctl.h> 4391126Smsmith#include <sys/unistd.h> 4491640Siwasaki#include <sys/power.h> 4567761Smsmith 46148138Sume#include "cpufreq_if.h" 47148138Sume 48193530Sjkim#include <contrib/dev/acpica/include/acpi.h> 49193530Sjkim#include <contrib/dev/acpica/include/accommon.h> 50193530Sjkim 5167761Smsmith#include <dev/acpica/acpivar.h> 5267761Smsmith 53119529Snjl/* Hooks for the ACPI CA debugging infrastructure */ 5478999Smsmith#define _COMPONENT ACPI_THERMAL 5591126SmsmithACPI_MODULE_NAME("THERMAL") 5669744Smsmith 5771874Smsmith#define TZ_ZEROC 2732 58160657Snjl#define TZ_KELVTOC(x) (((x) - TZ_ZEROC) / 10), abs(((x) - TZ_ZEROC) % 10) 5967761Smsmith 60125366Snjl#define TZ_NOTIFY_TEMPERATURE 0x80 /* Temperature changed. */ 61125366Snjl#define TZ_NOTIFY_LEVELS 0x81 /* Cooling levels changed. */ 62125366Snjl#define TZ_NOTIFY_DEVICES 0x82 /* Device lists changed. */ 63125366Snjl#define TZ_NOTIFY_CRITICAL 0xcc /* Fake notify that _CRT/_HOT reached. */ 6478915Smsmith 65125335Snjl/* Check for temperature changes every 10 seconds by default */ 66125335Snjl#define TZ_POLLRATE 10 6778915Smsmith 68125335Snjl/* Make sure the reported temperature is valid for this number of polls. */ 69125335Snjl#define TZ_VALIDCHECKS 3 70125335Snjl 71125366Snjl/* Notify the user we will be shutting down in one more poll cycle. */ 72125366Snjl#define TZ_NOTIFYCOUNT (TZ_VALIDCHECKS - 1) 73125366Snjl 74119529Snjl/* ACPI spec defines this */ 75119529Snjl#define TZ_NUMLEVELS 10 7679375Smsmithstruct acpi_tz_zone { 7778915Smsmith int ac[TZ_NUMLEVELS]; 7878915Smsmith ACPI_BUFFER al[TZ_NUMLEVELS]; 7978915Smsmith int crt; 8078915Smsmith int hot; 8178915Smsmith ACPI_BUFFER psl; 8278915Smsmith int psv; 8378915Smsmith int tc1; 8478915Smsmith int tc2; 8578915Smsmith int tsp; 8678915Smsmith int tzp; 8778915Smsmith}; 8878915Smsmith 8967761Smsmithstruct acpi_tz_softc { 90119529Snjl device_t tz_dev; 91119529Snjl ACPI_HANDLE tz_handle; /*Thermal zone handle*/ 92119529Snjl int tz_temperature; /*Current temperature*/ 93119529Snjl int tz_active; /*Current active cooling*/ 9479375Smsmith#define TZ_ACTIVE_NONE -1 95178506Srpaulo#define TZ_ACTIVE_UNKNOWN -2 96119529Snjl int tz_requested; /*Minimum active cooling*/ 97119529Snjl int tz_thflags; /*Current temp-related flags*/ 9879375Smsmith#define TZ_THFLAG_NONE 0 9979375Smsmith#define TZ_THFLAG_PSV (1<<0) 10079375Smsmith#define TZ_THFLAG_HOT (1<<2) 101148138Sume#define TZ_THFLAG_CRT (1<<3) 10279283Smsmith int tz_flags; 103119529Snjl#define TZ_FLAG_NO_SCP (1<<0) /*No _SCP method*/ 104119529Snjl#define TZ_FLAG_GETPROFILE (1<<1) /*Get power_profile in timeout*/ 105133624Snjl#define TZ_FLAG_GETSETTINGS (1<<2) /*Get devs/setpoints*/ 106119529Snjl struct timespec tz_cooling_started; 107119529Snjl /*Current cooling starting time*/ 10879283Smsmith 109119529Snjl struct sysctl_ctx_list tz_sysctl_ctx; 11079283Smsmith struct sysctl_oid *tz_sysctl_tree; 111133624Snjl eventhandler_tag tz_event; 112133624Snjl 113119529Snjl struct acpi_tz_zone tz_zone; /*Thermal zone parameters*/ 114125335Snjl int tz_validchecks; 115148138Sume 116148138Sume /* passive cooling */ 117148138Sume struct proc *tz_cooling_proc; 118148703Sume int tz_cooling_proc_running; 119148138Sume int tz_cooling_enabled; 120148138Sume int tz_cooling_active; 121148138Sume int tz_cooling_updated; 122149201Sume int tz_cooling_saved_freq; 12367761Smsmith}; 12467761Smsmith 125148138Sume#define CPUFREQ_MAX_LEVELS 64 /* XXX cpufreq should export this */ 126148138Sume 12767761Smsmithstatic int acpi_tz_probe(device_t dev); 12867761Smsmithstatic int acpi_tz_attach(device_t dev); 12978915Smsmithstatic int acpi_tz_establish(struct acpi_tz_softc *sc); 130119529Snjlstatic void acpi_tz_monitor(void *Context); 13178915Smsmithstatic void acpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg); 13278915Smsmithstatic void acpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg); 133119529Snjlstatic void acpi_tz_getparam(struct acpi_tz_softc *sc, char *node, 134119529Snjl int *data); 13579283Smsmithstatic void acpi_tz_sanity(struct acpi_tz_softc *sc, int *val, char *what); 13679375Smsmithstatic int acpi_tz_active_sysctl(SYSCTL_HANDLER_ARGS); 137148138Sumestatic int acpi_tz_cooling_sysctl(SYSCTL_HANDLER_ARGS); 138160657Snjlstatic int acpi_tz_temp_sysctl(SYSCTL_HANDLER_ARGS); 139174889Sumestatic int acpi_tz_passive_sysctl(SYSCTL_HANDLER_ARGS); 140119529Snjlstatic void acpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, 141119529Snjl void *context); 142133624Snjlstatic void acpi_tz_signal(struct acpi_tz_softc *sc, int flags); 143133624Snjlstatic void acpi_tz_timeout(struct acpi_tz_softc *sc, int flags); 14491640Siwasakistatic void acpi_tz_power_profile(void *arg); 14591126Smsmithstatic void acpi_tz_thread(void *arg); 146148138Sumestatic int acpi_tz_cooling_is_available(struct acpi_tz_softc *sc); 147148138Sumestatic int acpi_tz_cooling_thread_start(struct acpi_tz_softc *sc); 14891126Smsmith 14967761Smsmithstatic device_method_t acpi_tz_methods[] = { 15067761Smsmith /* Device interface */ 15167761Smsmith DEVMETHOD(device_probe, acpi_tz_probe), 15267761Smsmith DEVMETHOD(device_attach, acpi_tz_attach), 15367761Smsmith 15467761Smsmith {0, 0} 15567761Smsmith}; 15667761Smsmith 15767761Smsmithstatic driver_t acpi_tz_driver = { 15867761Smsmith "acpi_tz", 15967761Smsmith acpi_tz_methods, 16067761Smsmith sizeof(struct acpi_tz_softc), 16167761Smsmith}; 16267761Smsmith 16389054Smsmithstatic devclass_t acpi_tz_devclass; 16467761SmsmithDRIVER_MODULE(acpi_tz, acpi, acpi_tz_driver, acpi_tz_devclass, 0, 0); 165128071SnjlMODULE_DEPEND(acpi_tz, acpi, 1, 1, 1); 16667761Smsmith 16779283Smsmithstatic struct sysctl_ctx_list acpi_tz_sysctl_ctx; 16879283Smsmithstatic struct sysctl_oid *acpi_tz_sysctl_tree; 16979283Smsmith 170119529Snjl/* Minimum cooling run time */ 171160657Snjlstatic int acpi_tz_min_runtime; 17288420Siwasakistatic int acpi_tz_polling_rate = TZ_POLLRATE; 173160657Snjlstatic int acpi_tz_override; 17485699Siwasaki 175119529Snjl/* Timezone polling thread */ 176119529Snjlstatic struct proc *acpi_tz_proc; 177133624SnjlACPI_LOCK_DECL(thermal, "ACPI thermal zone"); 178119529Snjl 179176329Sumestatic int acpi_tz_cooling_unit = -1; 180176329Sume 18167761Smsmithstatic int 18267761Smsmithacpi_tz_probe(device_t dev) 18367761Smsmith{ 18478999Smsmith int result; 185148138Sume 186119529Snjl if (acpi_get_type(dev) == ACPI_TYPE_THERMAL && !acpi_disabled("thermal")) { 187120453Snjl device_set_desc(dev, "Thermal Zone"); 18878999Smsmith result = -10; 189133624Snjl } else 19078999Smsmith result = ENXIO; 191119529Snjl return (result); 19267761Smsmith} 19367761Smsmith 19467761Smsmithstatic int 19567761Smsmithacpi_tz_attach(device_t dev) 19667761Smsmith{ 19767761Smsmith struct acpi_tz_softc *sc; 19879283Smsmith struct acpi_softc *acpi_sc; 19978915Smsmith int error; 20079283Smsmith char oidname[8]; 20167761Smsmith 20296926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 20369744Smsmith 20467761Smsmith sc = device_get_softc(dev); 20567761Smsmith sc->tz_dev = dev; 20667761Smsmith sc->tz_handle = acpi_get_handle(dev); 20779375Smsmith sc->tz_requested = TZ_ACTIVE_NONE; 208178506Srpaulo sc->tz_active = TZ_ACTIVE_UNKNOWN; 209135548Snjl sc->tz_thflags = TZ_THFLAG_NONE; 210148138Sume sc->tz_cooling_proc = NULL; 211148703Sume sc->tz_cooling_proc_running = FALSE; 212148138Sume sc->tz_cooling_active = FALSE; 213148138Sume sc->tz_cooling_updated = FALSE; 214176329Sume sc->tz_cooling_enabled = FALSE; 21567761Smsmith 21678915Smsmith /* 21778915Smsmith * Parse the current state of the thermal zone and build control 218133624Snjl * structures. We don't need to worry about interference with the 219133624Snjl * control thread since we haven't fully attached this device yet. 22078915Smsmith */ 22178915Smsmith if ((error = acpi_tz_establish(sc)) != 0) 222133624Snjl return (error); 223133624Snjl 22478915Smsmith /* 22578915Smsmith * Register for any Notify events sent to this zone. 22678915Smsmith */ 227148138Sume AcpiInstallNotifyHandler(sc->tz_handle, ACPI_DEVICE_NOTIFY, 22878999Smsmith acpi_tz_notify_handler, sc); 22970271Stakawata 23071874Smsmith /* 23179283Smsmith * Create our sysctl nodes. 23279283Smsmith * 23379283Smsmith * XXX we need a mechanism for adding nodes under ACPI. 23479283Smsmith */ 23579283Smsmith if (device_get_unit(dev) == 0) { 23679283Smsmith acpi_sc = acpi_device_get_parent_softc(dev); 23779283Smsmith sysctl_ctx_init(&acpi_tz_sysctl_ctx); 23879283Smsmith acpi_tz_sysctl_tree = SYSCTL_ADD_NODE(&acpi_tz_sysctl_ctx, 239119529Snjl SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), 240119529Snjl OID_AUTO, "thermal", CTLFLAG_RD, 0, ""); 24185699Siwasaki SYSCTL_ADD_INT(&acpi_tz_sysctl_ctx, 24285699Siwasaki SYSCTL_CHILDREN(acpi_tz_sysctl_tree), 243159476Snjl OID_AUTO, "min_runtime", CTLFLAG_RW, 244119529Snjl &acpi_tz_min_runtime, 0, 245119529Snjl "minimum cooling run time in sec"); 24688420Siwasaki SYSCTL_ADD_INT(&acpi_tz_sysctl_ctx, 24788420Siwasaki SYSCTL_CHILDREN(acpi_tz_sysctl_tree), 248159476Snjl OID_AUTO, "polling_rate", CTLFLAG_RW, 24988420Siwasaki &acpi_tz_polling_rate, 0, "monitor polling rate"); 250160657Snjl SYSCTL_ADD_INT(&acpi_tz_sysctl_ctx, 251160657Snjl SYSCTL_CHILDREN(acpi_tz_sysctl_tree), OID_AUTO, 252160657Snjl "user_override", CTLFLAG_RW, &acpi_tz_override, 0, 253160657Snjl "allow override of thermal settings"); 25479283Smsmith } 25579283Smsmith sysctl_ctx_init(&sc->tz_sysctl_ctx); 25679283Smsmith sprintf(oidname, "tz%d", device_get_unit(dev)); 25779283Smsmith sc->tz_sysctl_tree = SYSCTL_ADD_NODE(&sc->tz_sysctl_ctx, 258119529Snjl SYSCTL_CHILDREN(acpi_tz_sysctl_tree), 259119529Snjl OID_AUTO, oidname, CTLFLAG_RD, 0, ""); 26079375Smsmith SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 261220798Smdf OID_AUTO, "temperature", CTLTYPE_INT | CTLFLAG_RD, 262220798Smdf &sc->tz_temperature, 0, sysctl_handle_int, 263220798Smdf "IK", "current thermal zone temperature"); 264220798Smdf SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 26579375Smsmith OID_AUTO, "active", CTLTYPE_INT | CTLFLAG_RW, 266160657Snjl sc, 0, acpi_tz_active_sysctl, "I", "cooling is active"); 267148138Sume SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 268148138Sume OID_AUTO, "passive_cooling", CTLTYPE_INT | CTLFLAG_RW, 269160657Snjl sc, 0, acpi_tz_cooling_sysctl, "I", 270160657Snjl "enable passive (speed reduction) cooling"); 271148138Sume 27279283Smsmith SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 27379375Smsmith OID_AUTO, "thermal_flags", CTLFLAG_RD, 27479375Smsmith &sc->tz_thflags, 0, "thermal zone flags"); 275160657Snjl SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 276160657Snjl OID_AUTO, "_PSV", CTLTYPE_INT | CTLFLAG_RW, 277160657Snjl sc, offsetof(struct acpi_tz_softc, tz_zone.psv), 278160657Snjl acpi_tz_temp_sysctl, "IK", "passive cooling temp setpoint"); 279160657Snjl SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 280160657Snjl OID_AUTO, "_HOT", CTLTYPE_INT | CTLFLAG_RW, 281160657Snjl sc, offsetof(struct acpi_tz_softc, tz_zone.hot), 282160657Snjl acpi_tz_temp_sysctl, "IK", 283160657Snjl "too hot temp setpoint (suspend now)"); 284160657Snjl SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 285160657Snjl OID_AUTO, "_CRT", CTLTYPE_INT | CTLFLAG_RW, 286160657Snjl sc, offsetof(struct acpi_tz_softc, tz_zone.crt), 287160657Snjl acpi_tz_temp_sysctl, "IK", 288160657Snjl "critical temp setpoint (shutdown now)"); 289174889Sume SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 290220798Smdf OID_AUTO, "_ACx", CTLTYPE_INT | CTLFLAG_RD, 291220871Smdf &sc->tz_zone.ac, sizeof(sc->tz_zone.ac), 292220871Smdf sysctl_handle_opaque, "IK", ""); 293220798Smdf SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 294174889Sume OID_AUTO, "_TC1", CTLTYPE_INT | CTLFLAG_RW, 295174889Sume sc, offsetof(struct acpi_tz_softc, tz_zone.tc1), 296174889Sume acpi_tz_passive_sysctl, "I", 297174889Sume "thermal constant 1 for passive cooling"); 298174889Sume SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 299174889Sume OID_AUTO, "_TC2", CTLTYPE_INT | CTLFLAG_RW, 300174889Sume sc, offsetof(struct acpi_tz_softc, tz_zone.tc2), 301174889Sume acpi_tz_passive_sysctl, "I", 302174889Sume "thermal constant 2 for passive cooling"); 303174889Sume SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 304174889Sume OID_AUTO, "_TSP", CTLTYPE_INT | CTLFLAG_RW, 305174889Sume sc, offsetof(struct acpi_tz_softc, tz_zone.tsp), 306174889Sume acpi_tz_passive_sysctl, "I", 307174889Sume "thermal sampling period for passive cooling"); 30879283Smsmith 30979283Smsmith /* 310148138Sume * Create thread to service all of the thermal zones. Register 311148138Sume * our power profile event handler. 31279375Smsmith */ 313133624Snjl sc->tz_event = EVENTHANDLER_REGISTER(power_profile_change, 314133624Snjl acpi_tz_power_profile, sc, 0); 315133624Snjl if (acpi_tz_proc == NULL) { 316172836Sjulian error = kproc_create(acpi_tz_thread, NULL, &acpi_tz_proc, 317133624Snjl RFHIGHPID, 0, "acpi_thermal"); 318133624Snjl if (error != 0) { 319133624Snjl device_printf(sc->tz_dev, "could not create thread - %d", error); 320133624Snjl goto out; 321133624Snjl } 322133624Snjl } 32379375Smsmith 324176329Sume /* 325176329Sume * Create a thread to handle passive cooling for 1st zone which 326176329Sume * has _PSV, _TSP, _TC1 and _TC2. Users can enable it for other 327176329Sume * zones manually for now. 328176329Sume * 329176329Sume * XXX We enable only one zone to avoid multiple zones conflict 330176329Sume * with each other since cpufreq currently sets all CPUs to the 331176329Sume * given frequency whereas it's possible for different thermal 332176329Sume * zones to specify independent settings for multiple CPUs. 333176329Sume */ 334176329Sume if (acpi_tz_cooling_unit < 0 && acpi_tz_cooling_is_available(sc)) 335176329Sume sc->tz_cooling_enabled = TRUE; 336148138Sume if (sc->tz_cooling_enabled) { 337176329Sume error = acpi_tz_cooling_thread_start(sc); 338176329Sume if (error != 0) { 339148138Sume sc->tz_cooling_enabled = FALSE; 340176329Sume goto out; 341176329Sume } 342176329Sume acpi_tz_cooling_unit = device_get_unit(dev); 343148138Sume } 344148138Sume 34579375Smsmith /* 346133624Snjl * Flag the event handler for a manual invocation by our timeout. 347133624Snjl * We defer it like this so that the rest of the subsystem has time 348133624Snjl * to come up. Don't bother evaluating/printing the temperature at 349133624Snjl * this point; on many systems it'll be bogus until the EC is running. 35071874Smsmith */ 351133624Snjl sc->tz_flags |= TZ_FLAG_GETPROFILE; 35278999Smsmith 353133624Snjlout: 354133624Snjl if (error != 0) { 355133624Snjl EVENTHANDLER_DEREGISTER(power_profile_change, sc->tz_event); 356133624Snjl AcpiRemoveNotifyHandler(sc->tz_handle, ACPI_DEVICE_NOTIFY, 357133624Snjl acpi_tz_notify_handler); 358133624Snjl sysctl_ctx_free(&sc->tz_sysctl_ctx); 35991126Smsmith } 360119529Snjl return_VALUE (error); 36167761Smsmith} 36270271Stakawata 36378915Smsmith/* 36478915Smsmith * Parse the current state of this thermal zone and set up to use it. 36578915Smsmith * 36678915Smsmith * Note that we may have previous state, which will have to be discarded. 36778915Smsmith */ 36878915Smsmithstatic int 36978915Smsmithacpi_tz_establish(struct acpi_tz_softc *sc) 37078915Smsmith{ 37178915Smsmith ACPI_OBJECT *obj; 37278915Smsmith int i; 37378915Smsmith char nbuf[8]; 374148138Sume 37596926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 37678915Smsmith 377134909Snjl /* Erase any existing state. */ 37878915Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) 37979375Smsmith if (sc->tz_zone.al[i].Pointer != NULL) 38079375Smsmith AcpiOsFree(sc->tz_zone.al[i].Pointer); 38179375Smsmith if (sc->tz_zone.psl.Pointer != NULL) 38279375Smsmith AcpiOsFree(sc->tz_zone.psl.Pointer); 38378915Smsmith 384149449Sume /* 385149449Sume * XXX: We initialize only ACPI_BUFFER to avoid race condition 386149449Sume * with passive cooling thread which refers psv, tc1, tc2 and tsp. 387149449Sume */ 388149449Sume bzero(sc->tz_zone.ac, sizeof(sc->tz_zone.ac)); 389149449Sume bzero(sc->tz_zone.al, sizeof(sc->tz_zone.al)); 390149449Sume bzero(&sc->tz_zone.psl, sizeof(sc->tz_zone.psl)); 391149449Sume 392119529Snjl /* Evaluate thermal zone parameters. */ 39378915Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) { 39478915Smsmith sprintf(nbuf, "_AC%d", i); 39579375Smsmith acpi_tz_getparam(sc, nbuf, &sc->tz_zone.ac[i]); 39678915Smsmith sprintf(nbuf, "_AL%d", i); 39791126Smsmith sc->tz_zone.al[i].Length = ACPI_ALLOCATE_BUFFER; 39891126Smsmith sc->tz_zone.al[i].Pointer = NULL; 39991126Smsmith AcpiEvaluateObject(sc->tz_handle, nbuf, NULL, &sc->tz_zone.al[i]); 40079375Smsmith obj = (ACPI_OBJECT *)sc->tz_zone.al[i].Pointer; 40178915Smsmith if (obj != NULL) { 402119529Snjl /* Should be a package containing a list of power objects */ 40378915Smsmith if (obj->Type != ACPI_TYPE_PACKAGE) { 404119529Snjl device_printf(sc->tz_dev, "%s has unknown type %d, rejecting\n", 40578915Smsmith nbuf, obj->Type); 406119529Snjl return_VALUE (ENXIO); 40778915Smsmith } 40878915Smsmith } 40978915Smsmith } 41079375Smsmith acpi_tz_getparam(sc, "_CRT", &sc->tz_zone.crt); 41179375Smsmith acpi_tz_getparam(sc, "_HOT", &sc->tz_zone.hot); 41291126Smsmith sc->tz_zone.psl.Length = ACPI_ALLOCATE_BUFFER; 41391126Smsmith sc->tz_zone.psl.Pointer = NULL; 41491126Smsmith AcpiEvaluateObject(sc->tz_handle, "_PSL", NULL, &sc->tz_zone.psl); 41579375Smsmith acpi_tz_getparam(sc, "_PSV", &sc->tz_zone.psv); 41679375Smsmith acpi_tz_getparam(sc, "_TC1", &sc->tz_zone.tc1); 41779375Smsmith acpi_tz_getparam(sc, "_TC2", &sc->tz_zone.tc2); 41879375Smsmith acpi_tz_getparam(sc, "_TSP", &sc->tz_zone.tsp); 41979375Smsmith acpi_tz_getparam(sc, "_TZP", &sc->tz_zone.tzp); 42078915Smsmith 42178915Smsmith /* 42279283Smsmith * Sanity-check the values we've been given. 42379283Smsmith * 42479283Smsmith * XXX what do we do about systems that give us the same value for 42579283Smsmith * more than one of these setpoints? 42679283Smsmith */ 42779375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.crt, "_CRT"); 42879375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.hot, "_HOT"); 42979375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.psv, "_PSV"); 43079283Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) 43179375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.ac[i], "_ACx"); 43279283Smsmith 433119529Snjl return_VALUE (0); 43478915Smsmith} 43578915Smsmith 436133624Snjlstatic char *aclevel_string[] = { 437133624Snjl "NONE", "_AC0", "_AC1", "_AC2", "_AC3", "_AC4", 438133624Snjl "_AC5", "_AC6", "_AC7", "_AC8", "_AC9" 439133624Snjl}; 44085699Siwasaki 44185699Siwasakistatic __inline const char * 44285699Siwasakiacpi_tz_aclevel_string(int active) 44385699Siwasaki{ 444133624Snjl if (active < -1 || active >= TZ_NUMLEVELS) 445133624Snjl return (aclevel_string[0]); 44685699Siwasaki 447133624Snjl return (aclevel_string[active + 1]); 44885699Siwasaki} 44985699Siwasaki 45078915Smsmith/* 451149450Sume * Get the current temperature. 452149450Sume */ 453149450Sumestatic int 454149450Sumeacpi_tz_get_temperature(struct acpi_tz_softc *sc) 455149450Sume{ 456149450Sume int temp; 457149450Sume ACPI_STATUS status; 458167249Snjl static char *tmp_name = "_TMP"; 459149450Sume 460149482Skan ACPI_FUNCTION_NAME ("acpi_tz_get_temperature"); 461149482Skan 462167249Snjl /* Evaluate the thermal zone's _TMP method. */ 463167249Snjl status = acpi_GetInteger(sc->tz_handle, tmp_name, &temp); 464149450Sume if (ACPI_FAILURE(status)) { 465149450Sume ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 466149450Sume "error fetching current temperature -- %s\n", 467149450Sume AcpiFormatException(status)); 468149450Sume return (FALSE); 469149450Sume } 470149450Sume 471167249Snjl /* Check it for validity. */ 472167249Snjl acpi_tz_sanity(sc, &temp, tmp_name); 473167249Snjl if (temp == -1) 474167249Snjl return (FALSE); 475167249Snjl 476149450Sume ACPI_DEBUG_PRINT((ACPI_DB_VALUES, "got %d.%dC\n", TZ_KELVTOC(temp))); 477149450Sume sc->tz_temperature = temp; 478149450Sume return (TRUE); 479149450Sume} 480149450Sume 481149450Sume/* 48278915Smsmith * Evaluate the condition of a thermal zone, take appropriate actions. 48378915Smsmith */ 48471874Smsmithstatic void 485119529Snjlacpi_tz_monitor(void *Context) 48671874Smsmith{ 487119529Snjl struct acpi_tz_softc *sc; 488119529Snjl struct timespec curtime; 48979283Smsmith int temp; 49078915Smsmith int i; 49179283Smsmith int newactive, newflags; 49270271Stakawata 49396926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 49470271Stakawata 495119529Snjl sc = (struct acpi_tz_softc *)Context; 49688420Siwasaki 497119529Snjl /* Get the current temperature. */ 498149450Sume if (!acpi_tz_get_temperature(sc)) { 49978915Smsmith /* XXX disable zone? go to max cooling? */ 500133624Snjl return_VOID; 50171874Smsmith } 502149450Sume temp = sc->tz_temperature; 50388420Siwasaki 50478915Smsmith /* 50578915Smsmith * Work out what we ought to be doing right now. 50679283Smsmith * 50779283Smsmith * Note that the _ACx levels sort from hot to cold. 50878915Smsmith */ 50979283Smsmith newactive = TZ_ACTIVE_NONE; 51079375Smsmith for (i = TZ_NUMLEVELS - 1; i >= 0; i--) { 511142195Snjl if (sc->tz_zone.ac[i] != -1 && temp >= sc->tz_zone.ac[i]) { 51279283Smsmith newactive = i; 51382967Siwasaki if (sc->tz_active != newactive) { 514119529Snjl ACPI_VPRINT(sc->tz_dev, 515119529Snjl acpi_device_get_parent_softc(sc->tz_dev), 516119529Snjl "_AC%d: temperature %d.%d >= setpoint %d.%d\n", i, 517119529Snjl TZ_KELVTOC(temp), TZ_KELVTOC(sc->tz_zone.ac[i])); 51882967Siwasaki } 51979375Smsmith } 52079375Smsmith } 52179283Smsmith 52285699Siwasaki /* 52385699Siwasaki * We are going to get _ACx level down (colder side), but give a guaranteed 52485699Siwasaki * minimum cooling run time if requested. 52585699Siwasaki */ 52685699Siwasaki if (acpi_tz_min_runtime > 0 && sc->tz_active != TZ_ACTIVE_NONE && 527178506Srpaulo sc->tz_active != TZ_ACTIVE_UNKNOWN && 52885699Siwasaki (newactive == TZ_ACTIVE_NONE || newactive > sc->tz_active)) { 529119529Snjl 53085699Siwasaki getnanotime(&curtime); 53185699Siwasaki timespecsub(&curtime, &sc->tz_cooling_started); 532119529Snjl if (curtime.tv_sec < acpi_tz_min_runtime) 53385699Siwasaki newactive = sc->tz_active; 53485699Siwasaki } 53585699Siwasaki 536119529Snjl /* Handle user override of active mode */ 537176327Srpaulo if (sc->tz_requested != TZ_ACTIVE_NONE && (newactive == TZ_ACTIVE_NONE 538176327Srpaulo || sc->tz_requested < newactive)) 53979375Smsmith newactive = sc->tz_requested; 54078915Smsmith 54179375Smsmith /* update temperature-related flags */ 54279375Smsmith newflags = TZ_THFLAG_NONE; 543124439Snjl if (sc->tz_zone.psv != -1 && temp >= sc->tz_zone.psv) 54479375Smsmith newflags |= TZ_THFLAG_PSV; 545124439Snjl if (sc->tz_zone.hot != -1 && temp >= sc->tz_zone.hot) 54679375Smsmith newflags |= TZ_THFLAG_HOT; 547124439Snjl if (sc->tz_zone.crt != -1 && temp >= sc->tz_zone.crt) 54879375Smsmith newflags |= TZ_THFLAG_CRT; 54979375Smsmith 550119529Snjl /* If the active cooling state has changed, we have to switch things. */ 551178506Srpaulo if (sc->tz_active == TZ_ACTIVE_UNKNOWN) { 552178506Srpaulo /* 553178506Srpaulo * We don't know which cooling device is on or off, 554178506Srpaulo * so stop them all, because we now know which 555178506Srpaulo * should be on (if any). 556178506Srpaulo */ 557178506Srpaulo for (i = 0; i < TZ_NUMLEVELS; i++) { 558178506Srpaulo if (sc->tz_zone.al[i].Pointer != NULL) { 559178506Srpaulo acpi_ForeachPackageObject( 560178506Srpaulo (ACPI_OBJECT *)sc->tz_zone.al[i].Pointer, 561178506Srpaulo acpi_tz_switch_cooler_off, sc); 562178506Srpaulo } 563178506Srpaulo } 564178506Srpaulo /* now we know that all devices are off */ 565178506Srpaulo sc->tz_active = TZ_ACTIVE_NONE; 566178506Srpaulo } 567178506Srpaulo 56879283Smsmith if (newactive != sc->tz_active) { 569119529Snjl /* Turn off the cooling devices that are on, if any are */ 57079283Smsmith if (sc->tz_active != TZ_ACTIVE_NONE) 571119529Snjl acpi_ForeachPackageObject( 572119529Snjl (ACPI_OBJECT *)sc->tz_zone.al[sc->tz_active].Pointer, 573119529Snjl acpi_tz_switch_cooler_off, sc); 57478915Smsmith 575119529Snjl /* Turn on cooling devices that are required, if any are */ 576119529Snjl if (newactive != TZ_ACTIVE_NONE) { 577119529Snjl acpi_ForeachPackageObject( 578119529Snjl (ACPI_OBJECT *)sc->tz_zone.al[newactive].Pointer, 579119529Snjl acpi_tz_switch_cooler_on, sc); 580119529Snjl } 58186552Siwasaki ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 582119529Snjl "switched from %s to %s: %d.%dC\n", 583119529Snjl acpi_tz_aclevel_string(sc->tz_active), 584119529Snjl acpi_tz_aclevel_string(newactive), TZ_KELVTOC(temp)); 58579283Smsmith sc->tz_active = newactive; 586142195Snjl getnanotime(&sc->tz_cooling_started); 58779283Smsmith } 58878915Smsmith 589119529Snjl /* XXX (de)activate any passive cooling that may be required. */ 59078915Smsmith 59178915Smsmith /* 592125335Snjl * If the temperature is at _HOT or _CRT, increment our event count. 593125335Snjl * If it has occurred enough times, shutdown the system. This is 594125335Snjl * needed because some systems will report an invalid high temperature 595125335Snjl * for one poll cycle. It is suspected this is due to the embedded 596125335Snjl * controller timing out. A typical value is 138C for one cycle on 597125335Snjl * a system that is otherwise 65C. 598125366Snjl * 599125366Snjl * If we're almost at that threshold, notify the user through devd(8). 60078915Smsmith */ 601125335Snjl if ((newflags & (TZ_THFLAG_HOT | TZ_THFLAG_CRT)) != 0) { 602125366Snjl sc->tz_validchecks++; 603125366Snjl if (sc->tz_validchecks == TZ_VALIDCHECKS) { 604125335Snjl device_printf(sc->tz_dev, 605125335Snjl "WARNING - current temperature (%d.%dC) exceeds safe limits\n", 606125335Snjl TZ_KELVTOC(sc->tz_temperature)); 607125335Snjl shutdown_nice(RB_POWEROFF); 608125366Snjl } else if (sc->tz_validchecks == TZ_NOTIFYCOUNT) 609125366Snjl acpi_UserNotify("Thermal", sc->tz_handle, TZ_NOTIFY_CRITICAL); 610125335Snjl } else { 611125335Snjl sc->tz_validchecks = 0; 61278915Smsmith } 61379375Smsmith sc->tz_thflags = newflags; 61478915Smsmith 61571874Smsmith return_VOID; 61671874Smsmith} 61770271Stakawata 61878915Smsmith/* 619148138Sume * Given an object, verify that it's a reference to a device of some sort, 62078915Smsmith * and try to switch it off. 62178915Smsmith */ 62278915Smsmithstatic void 62378915Smsmithacpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg) 62478915Smsmith{ 625128047Snjl ACPI_HANDLE cooler; 62678915Smsmith 62796926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 62878915Smsmith 629128047Snjl cooler = acpi_GetReference(NULL, obj); 630128047Snjl if (cooler == NULL) { 631128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get handle\n")); 632128047Snjl return_VOID; 633128047Snjl } 634102470Siwasaki 635128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s off\n", 636128047Snjl acpi_name(cooler))); 637128150Snjl acpi_pwr_switch_consumer(cooler, ACPI_STATE_D3); 638119529Snjl 63979375Smsmith return_VOID; 64078915Smsmith} 64178915Smsmith 64278915Smsmith/* 643148138Sume * Given an object, verify that it's a reference to a device of some sort, 64478915Smsmith * and try to switch it on. 64578915Smsmith * 646128047Snjl * XXX replication of off/on function code is bad. 64778915Smsmith */ 64878915Smsmithstatic void 64978915Smsmithacpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg) 65078915Smsmith{ 65178915Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg; 65278999Smsmith ACPI_HANDLE cooler; 65379375Smsmith ACPI_STATUS status; 654148138Sume 65596926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 65678915Smsmith 657128047Snjl cooler = acpi_GetReference(NULL, obj); 658128047Snjl if (cooler == NULL) { 659128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get handle\n")); 660128047Snjl return_VOID; 661128047Snjl } 662102470Siwasaki 663128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s on\n", 664128047Snjl acpi_name(cooler))); 665128047Snjl status = acpi_pwr_switch_consumer(cooler, ACPI_STATE_D0); 666128047Snjl if (ACPI_FAILURE(status)) { 667128047Snjl ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 668128047Snjl "failed to activate %s - %s\n", acpi_name(cooler), 669128047Snjl AcpiFormatException(status)); 67078915Smsmith } 671119529Snjl 672119529Snjl return_VOID; 67378915Smsmith} 67478915Smsmith 67578915Smsmith/* 67678915Smsmith * Read/debug-print a parameter, default it to -1. 67778915Smsmith */ 67878915Smsmithstatic void 67978915Smsmithacpi_tz_getparam(struct acpi_tz_softc *sc, char *node, int *data) 68078915Smsmith{ 68178915Smsmith 68296926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 68378915Smsmith 684126560Snjl if (ACPI_FAILURE(acpi_GetInteger(sc->tz_handle, node, data))) { 68578915Smsmith *data = -1; 68678915Smsmith } else { 687119529Snjl ACPI_DEBUG_PRINT((ACPI_DB_VALUES, "%s.%s = %d\n", 688119529Snjl acpi_name(sc->tz_handle), node, *data)); 68978915Smsmith } 690119529Snjl 691148138Sume return_VOID; 69278915Smsmith} 69379283Smsmith 69479283Smsmith/* 69579283Smsmith * Sanity-check a temperature value. Assume that setpoints 696167249Snjl * should be between 0C and 200C. 69779283Smsmith */ 69879283Smsmithstatic void 69979283Smsmithacpi_tz_sanity(struct acpi_tz_softc *sc, int *val, char *what) 70079283Smsmith{ 701167249Snjl if (*val != -1 && (*val < TZ_ZEROC || *val > TZ_ZEROC + 2000)) { 70279283Smsmith device_printf(sc->tz_dev, "%s value is absurd, ignored (%d.%dC)\n", 70379283Smsmith what, TZ_KELVTOC(*val)); 70479283Smsmith *val = -1; 70579283Smsmith } 70679283Smsmith} 70779375Smsmith 70879375Smsmith/* 70979375Smsmith * Respond to a sysctl on the active state node. 710148138Sume */ 71179375Smsmithstatic int 71279375Smsmithacpi_tz_active_sysctl(SYSCTL_HANDLER_ARGS) 71379375Smsmith{ 71479375Smsmith struct acpi_tz_softc *sc; 71579375Smsmith int active; 71679375Smsmith int error; 71779375Smsmith 71879375Smsmith sc = (struct acpi_tz_softc *)oidp->oid_arg1; 71979375Smsmith active = sc->tz_active; 72079375Smsmith error = sysctl_handle_int(oidp, &active, 0, req); 72179375Smsmith 722119529Snjl /* Error or no new value */ 723119529Snjl if (error != 0 || req->newptr == NULL) 724133624Snjl return (error); 725133624Snjl if (active < -1 || active >= TZ_NUMLEVELS) 726133624Snjl return (EINVAL); 72779375Smsmith 728119529Snjl /* Set new preferred level and re-switch */ 72979375Smsmith sc->tz_requested = active; 730133624Snjl acpi_tz_signal(sc, 0); 731133624Snjl return (0); 73279375Smsmith} 73379375Smsmith 734148138Sumestatic int 735148138Sumeacpi_tz_cooling_sysctl(SYSCTL_HANDLER_ARGS) 736148138Sume{ 737148138Sume struct acpi_tz_softc *sc; 738148138Sume int enabled, error; 739148138Sume 740148138Sume sc = (struct acpi_tz_softc *)oidp->oid_arg1; 741148138Sume enabled = sc->tz_cooling_enabled; 742148138Sume error = sysctl_handle_int(oidp, &enabled, 0, req); 743148138Sume 744148138Sume /* Error or no new value */ 745148138Sume if (error != 0 || req->newptr == NULL) 746148138Sume return (error); 747148138Sume if (enabled != TRUE && enabled != FALSE) 748148138Sume return (EINVAL); 749148138Sume 750148138Sume if (enabled) { 751148138Sume if (acpi_tz_cooling_is_available(sc)) 752148138Sume error = acpi_tz_cooling_thread_start(sc); 753148138Sume else 754148138Sume error = ENODEV; 755148138Sume if (error) 756148138Sume enabled = FALSE; 757148138Sume } 758148138Sume sc->tz_cooling_enabled = enabled; 759148138Sume return (error); 760148138Sume} 761148138Sume 762160657Snjlstatic int 763160657Snjlacpi_tz_temp_sysctl(SYSCTL_HANDLER_ARGS) 764160657Snjl{ 765160657Snjl struct acpi_tz_softc *sc; 766160657Snjl int temp, *temp_ptr; 767160657Snjl int error; 768160657Snjl 769160657Snjl sc = oidp->oid_arg1; 770160657Snjl temp_ptr = (int *)((uintptr_t)sc + oidp->oid_arg2); 771160657Snjl temp = *temp_ptr; 772160657Snjl error = sysctl_handle_int(oidp, &temp, 0, req); 773160657Snjl 774160657Snjl /* Error or no new value */ 775160657Snjl if (error != 0 || req->newptr == NULL) 776160657Snjl return (error); 777160657Snjl 778160657Snjl /* Only allow changing settings if override is set. */ 779160657Snjl if (!acpi_tz_override) 780160657Snjl return (EPERM); 781160657Snjl 782160657Snjl /* Check user-supplied value for sanity. */ 783160657Snjl acpi_tz_sanity(sc, &temp, "user-supplied temp"); 784160657Snjl if (temp == -1) 785160657Snjl return (EINVAL); 786160657Snjl 787160657Snjl *temp_ptr = temp; 788160657Snjl return (0); 789160657Snjl} 790160657Snjl 791174889Sumestatic int 792174889Sumeacpi_tz_passive_sysctl(SYSCTL_HANDLER_ARGS) 793174889Sume{ 794174889Sume struct acpi_tz_softc *sc; 795174889Sume int val, *val_ptr; 796174889Sume int error; 797174889Sume 798174889Sume sc = oidp->oid_arg1; 799174889Sume val_ptr = (int *)((uintptr_t)sc + oidp->oid_arg2); 800174889Sume val = *val_ptr; 801174889Sume error = sysctl_handle_int(oidp, &val, 0, req); 802174889Sume 803174889Sume /* Error or no new value */ 804174889Sume if (error != 0 || req->newptr == NULL) 805174889Sume return (error); 806174889Sume 807174889Sume /* Only allow changing settings if override is set. */ 808174889Sume if (!acpi_tz_override) 809174889Sume return (EPERM); 810174889Sume 811174889Sume *val_ptr = val; 812174889Sume return (0); 813174889Sume} 814174889Sume 81578915Smsmithstatic void 81671874Smsmithacpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context) 81771874Smsmith{ 81878915Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)context; 81978915Smsmith 82096926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 82170271Stakawata 822133624Snjl switch (notify) { 82378915Smsmith case TZ_NOTIFY_TEMPERATURE: 824119529Snjl /* Temperature change occurred */ 825133624Snjl acpi_tz_signal(sc, 0); 82678915Smsmith break; 82778915Smsmith case TZ_NOTIFY_DEVICES: 82878915Smsmith case TZ_NOTIFY_LEVELS: 829119529Snjl /* Zone devices/setpoints changed */ 830133624Snjl acpi_tz_signal(sc, TZ_FLAG_GETSETTINGS); 83178915Smsmith break; 83278915Smsmith default: 83386552Siwasaki ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 834119529Snjl "unknown Notify event 0x%x\n", notify); 83578915Smsmith break; 83671874Smsmith } 837119529Snjl 838121493Snjl acpi_UserNotify("Thermal", h, notify); 839121493Snjl 84071874Smsmith return_VOID; 84171874Smsmith} 84270271Stakawata 843133624Snjlstatic void 844133624Snjlacpi_tz_signal(struct acpi_tz_softc *sc, int flags) 845133624Snjl{ 846133624Snjl ACPI_LOCK(thermal); 847133624Snjl sc->tz_flags |= flags; 848133624Snjl ACPI_UNLOCK(thermal); 849133624Snjl wakeup(&acpi_tz_proc); 850133624Snjl} 851133624Snjl 85278915Smsmith/* 853134909Snjl * Notifies can be generated asynchronously but have also been seen to be 854134909Snjl * triggered by other thermal methods. One system generates a notify of 855134909Snjl * 0x81 when the fan is turned on or off. Another generates it when _SCP 856134909Snjl * is called. To handle these situations, we check the zone via 857134909Snjl * acpi_tz_monitor() before evaluating changes to setpoints or the cooling 858134909Snjl * policy. 85978915Smsmith */ 86078915Smsmithstatic void 861133624Snjlacpi_tz_timeout(struct acpi_tz_softc *sc, int flags) 86278915Smsmith{ 863134909Snjl 864134909Snjl /* Check the current temperature and take action based on it */ 865134909Snjl acpi_tz_monitor(sc); 866134909Snjl 867133624Snjl /* If requested, get the power profile settings. */ 868133624Snjl if (flags & TZ_FLAG_GETPROFILE) 869133624Snjl acpi_tz_power_profile(sc); 87079375Smsmith 871134909Snjl /* 872134909Snjl * If requested, check for new devices/setpoints. After finding them, 873134909Snjl * check if we need to switch fans based on the new values. 874134909Snjl */ 875134909Snjl if (flags & TZ_FLAG_GETSETTINGS) { 876133624Snjl acpi_tz_establish(sc); 877134909Snjl acpi_tz_monitor(sc); 878134909Snjl } 87978915Smsmith 88078915Smsmith /* XXX passive cooling actions? */ 88178915Smsmith} 88279375Smsmith 88379375Smsmith/* 88479375Smsmith * System power profile may have changed; fetch and notify the 88579375Smsmith * thermal zone accordingly. 88679375Smsmith * 88779375Smsmith * Since this can be called from an arbitrary eventhandler, it needs 88879375Smsmith * to get the ACPI lock itself. 88979375Smsmith */ 89079375Smsmithstatic void 89191640Siwasakiacpi_tz_power_profile(void *arg) 89279375Smsmith{ 89379375Smsmith ACPI_STATUS status; 89479375Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg; 89591640Siwasaki int state; 89679375Smsmith 89791640Siwasaki state = power_profile_get_state(); 898119529Snjl if (state != POWER_PROFILE_PERFORMANCE && state != POWER_PROFILE_ECONOMY) 899119529Snjl return; 90091640Siwasaki 90179375Smsmith /* check that we haven't decided there's no _SCP method */ 902119529Snjl if ((sc->tz_flags & TZ_FLAG_NO_SCP) == 0) { 90379375Smsmith 904119529Snjl /* Call _SCP to set the new profile */ 905148138Sume status = acpi_SetInteger(sc->tz_handle, "_SCP", 906126560Snjl (state == POWER_PROFILE_PERFORMANCE) ? 0 : 1); 907119529Snjl if (ACPI_FAILURE(status)) { 90879385Smsmith if (status != AE_NOT_FOUND) 909119529Snjl ACPI_VPRINT(sc->tz_dev, 910119529Snjl acpi_device_get_parent_softc(sc->tz_dev), 911119529Snjl "can't evaluate %s._SCP - %s\n", 912119529Snjl acpi_name(sc->tz_handle), 913119529Snjl AcpiFormatException(status)); 91479375Smsmith sc->tz_flags |= TZ_FLAG_NO_SCP; 91579375Smsmith } else { 916119529Snjl /* We have to re-evaluate the entire zone now */ 917133624Snjl acpi_tz_signal(sc, TZ_FLAG_GETSETTINGS); 91879375Smsmith } 91979375Smsmith } 92079375Smsmith} 92179375Smsmith 92291126Smsmith/* 92391126Smsmith * Thermal zone monitor thread. 92491126Smsmith */ 92591126Smsmithstatic void 92691126Smsmithacpi_tz_thread(void *arg) 92791126Smsmith{ 92891126Smsmith device_t *devs; 92991126Smsmith int devcount, i; 930133624Snjl int flags; 931133624Snjl struct acpi_tz_softc **sc; 93291126Smsmith 93396926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 93491126Smsmith 93591126Smsmith devs = NULL; 93691126Smsmith devcount = 0; 937133624Snjl sc = NULL; 93891126Smsmith 93991126Smsmith for (;;) { 940133624Snjl /* If the number of devices has changed, re-evaluate. */ 941175014Sjhb if (devclass_get_count(acpi_tz_devclass) != devcount) { 942133624Snjl if (devs != NULL) { 943133624Snjl free(devs, M_TEMP); 944133624Snjl free(sc, M_TEMP); 945133624Snjl } 946133624Snjl devclass_get_devices(acpi_tz_devclass, &devs, &devcount); 947133624Snjl sc = malloc(sizeof(struct acpi_tz_softc *) * devcount, M_TEMP, 948133624Snjl M_WAITOK | M_ZERO); 949133624Snjl for (i = 0; i < devcount; i++) 950133624Snjl sc[i] = device_get_softc(devs[i]); 951133624Snjl } 95291126Smsmith 953133624Snjl /* Check for temperature events and act on them. */ 954133624Snjl for (i = 0; i < devcount; i++) { 955133624Snjl ACPI_LOCK(thermal); 956133624Snjl flags = sc[i]->tz_flags; 957133624Snjl sc[i]->tz_flags &= TZ_FLAG_NO_SCP; 958133624Snjl ACPI_UNLOCK(thermal); 959133624Snjl acpi_tz_timeout(sc[i], flags); 960133624Snjl } 96191215Smsmith 962133624Snjl /* If more work to do, don't go to sleep yet. */ 963133624Snjl ACPI_LOCK(thermal); 964133624Snjl for (i = 0; i < devcount; i++) { 965133624Snjl if (sc[i]->tz_flags & ~TZ_FLAG_NO_SCP) 966133624Snjl break; 967133624Snjl } 96891126Smsmith 969133624Snjl /* 970133624Snjl * If we have no more work, sleep for a while, setting PDROP so that 971133624Snjl * the mutex will not be reacquired. Otherwise, drop the mutex and 972133624Snjl * loop to handle more events. 973133624Snjl */ 974133624Snjl if (i == devcount) 975133624Snjl msleep(&acpi_tz_proc, &thermal_mutex, PZERO | PDROP, "tzpoll", 976133624Snjl hz * acpi_tz_polling_rate); 977133624Snjl else 978133624Snjl ACPI_UNLOCK(thermal); 97991126Smsmith } 98091126Smsmith} 981148138Sume 982148138Sumestatic int 983148138Sumeacpi_tz_cpufreq_restore(struct acpi_tz_softc *sc) 984148138Sume{ 985148138Sume device_t dev; 986148138Sume int error; 987148138Sume 988148138Sume if (!sc->tz_cooling_updated) 989148138Sume return (0); 990148138Sume if ((dev = devclass_get_device(devclass_find("cpufreq"), 0)) == NULL) 991148138Sume return (ENXIO); 992148138Sume ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 993149201Sume "temperature %d.%dC: resuming previous clock speed (%d MHz)\n", 994149201Sume TZ_KELVTOC(sc->tz_temperature), sc->tz_cooling_saved_freq); 995148138Sume error = CPUFREQ_SET(dev, NULL, CPUFREQ_PRIO_KERN); 996148138Sume if (error == 0) 997148138Sume sc->tz_cooling_updated = FALSE; 998148138Sume return (error); 999148138Sume} 1000148138Sume 1001148138Sumestatic int 1002148138Sumeacpi_tz_cpufreq_update(struct acpi_tz_softc *sc, int req) 1003148138Sume{ 1004148138Sume device_t dev; 1005148138Sume struct cf_level *levels; 1006148138Sume int num_levels, error, freq, desired_freq, perf, i; 1007148138Sume 1008148138Sume levels = malloc(CPUFREQ_MAX_LEVELS * sizeof(*levels), M_TEMP, M_NOWAIT); 1009148138Sume if (levels == NULL) 1010148138Sume return (ENOMEM); 1011148138Sume 1012148138Sume /* 1013148138Sume * Find the main device, cpufreq0. We don't yet support independent 1014148138Sume * CPU frequency control on SMP. 1015148138Sume */ 1016148138Sume if ((dev = devclass_get_device(devclass_find("cpufreq"), 0)) == NULL) { 1017148138Sume error = ENXIO; 1018148138Sume goto out; 1019148138Sume } 1020148138Sume 1021148138Sume /* Get the current frequency. */ 1022148138Sume error = CPUFREQ_GET(dev, &levels[0]); 1023148138Sume if (error) 1024148138Sume goto out; 1025148138Sume freq = levels[0].total_set.freq; 1026148138Sume 1027148138Sume /* Get the current available frequency levels. */ 1028148138Sume num_levels = CPUFREQ_MAX_LEVELS; 1029148138Sume error = CPUFREQ_LEVELS(dev, levels, &num_levels); 1030148138Sume if (error) { 1031148138Sume if (error == E2BIG) 1032148138Sume printf("cpufreq: need to increase CPUFREQ_MAX_LEVELS\n"); 1033148138Sume goto out; 1034148138Sume } 1035148138Sume 1036148138Sume /* Calculate the desired frequency as a percent of the max frequency. */ 1037148138Sume perf = 100 * freq / levels[0].total_set.freq - req; 1038148138Sume if (perf < 0) 1039148138Sume perf = 0; 1040148138Sume else if (perf > 100) 1041148138Sume perf = 100; 1042148138Sume desired_freq = levels[0].total_set.freq * perf / 100; 1043148138Sume 1044149201Sume if (desired_freq < freq) { 1045148138Sume /* Find the closest available frequency, rounding down. */ 1046148138Sume for (i = 0; i < num_levels; i++) 1047148138Sume if (levels[i].total_set.freq <= desired_freq) 1048148138Sume break; 1049148138Sume 1050148138Sume /* If we didn't find a relevant setting, use the lowest. */ 1051148138Sume if (i == num_levels) 1052148138Sume i--; 1053148138Sume } else { 1054149201Sume /* If we didn't decrease frequency yet, don't increase it. */ 1055149201Sume if (!sc->tz_cooling_updated) { 1056149201Sume sc->tz_cooling_active = FALSE; 1057149201Sume goto out; 1058149201Sume } 1059149201Sume 1060149201Sume /* Use saved cpu frequency as maximum value. */ 1061149201Sume if (desired_freq > sc->tz_cooling_saved_freq) 1062149201Sume desired_freq = sc->tz_cooling_saved_freq; 1063149201Sume 1064148138Sume /* Find the closest available frequency, rounding up. */ 1065148138Sume for (i = num_levels - 1; i >= 0; i--) 1066148138Sume if (levels[i].total_set.freq >= desired_freq) 1067148138Sume break; 1068148138Sume 1069148138Sume /* If we didn't find a relevant setting, use the highest. */ 1070148138Sume if (i == -1) 1071148138Sume i++; 1072148138Sume 1073149201Sume /* If we're going to the highest frequency, restore the old setting. */ 1074149201Sume if (i == 0 || desired_freq == sc->tz_cooling_saved_freq) { 1075149201Sume error = acpi_tz_cpufreq_restore(sc); 1076149201Sume if (error == 0) 1077149201Sume sc->tz_cooling_active = FALSE; 1078149201Sume goto out; 1079149201Sume } 1080148138Sume } 1081148138Sume 1082148138Sume /* If we are going to a new frequency, activate it. */ 1083148138Sume if (levels[i].total_set.freq != freq) { 1084148138Sume ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 1085148138Sume "temperature %d.%dC: %screasing clock speed " 1086148138Sume "from %d MHz to %d MHz\n", 1087148138Sume TZ_KELVTOC(sc->tz_temperature), 1088148138Sume (freq > levels[i].total_set.freq) ? "de" : "in", 1089148138Sume freq, levels[i].total_set.freq); 1090148138Sume error = CPUFREQ_SET(dev, &levels[i], CPUFREQ_PRIO_KERN); 1091149201Sume if (error == 0 && !sc->tz_cooling_updated) { 1092149201Sume sc->tz_cooling_saved_freq = freq; 1093148138Sume sc->tz_cooling_updated = TRUE; 1094149201Sume } 1095148138Sume } 1096148138Sume 1097148138Sumeout: 1098148138Sume if (levels) 1099148138Sume free(levels, M_TEMP); 1100148138Sume return (error); 1101148138Sume} 1102148138Sume 1103148138Sume/* 1104148138Sume * Passive cooling thread; monitors current temperature according to the 1105148138Sume * cooling interval and calculates whether to scale back CPU frequency. 1106148138Sume */ 1107148138Sumestatic void 1108148138Sumeacpi_tz_cooling_thread(void *arg) 1109148138Sume{ 1110148138Sume struct acpi_tz_softc *sc; 1111149450Sume int error, perf, curr_temp, prev_temp; 1112148138Sume 1113148138Sume ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 1114148138Sume 1115148138Sume sc = (struct acpi_tz_softc *)arg; 1116148138Sume 1117149450Sume prev_temp = sc->tz_temperature; 1118148138Sume while (sc->tz_cooling_enabled) { 1119149450Sume if (sc->tz_cooling_active) 1120149450Sume (void)acpi_tz_get_temperature(sc); 1121149450Sume curr_temp = sc->tz_temperature; 1122149450Sume if (curr_temp >= sc->tz_zone.psv) 1123148138Sume sc->tz_cooling_active = TRUE; 1124148138Sume if (sc->tz_cooling_active) { 1125149450Sume perf = sc->tz_zone.tc1 * (curr_temp - prev_temp) + 1126149450Sume sc->tz_zone.tc2 * (curr_temp - sc->tz_zone.psv); 1127148138Sume perf /= 10; 1128148138Sume 1129148138Sume if (perf != 0) { 1130148138Sume error = acpi_tz_cpufreq_update(sc, perf); 1131148138Sume 1132148138Sume /* 1133148138Sume * If error and not simply a higher priority setting was 1134148138Sume * active, disable cooling. 1135148138Sume */ 1136148138Sume if (error != 0 && error != EPERM) { 1137148138Sume device_printf(sc->tz_dev, 1138148138Sume "failed to set new freq, disabling passive cooling\n"); 1139148138Sume sc->tz_cooling_enabled = FALSE; 1140148138Sume } 1141148138Sume } 1142148138Sume } 1143149450Sume prev_temp = curr_temp; 1144148138Sume tsleep(&sc->tz_cooling_proc, PZERO, "cooling", 1145148138Sume hz * sc->tz_zone.tsp / 10); 1146148138Sume } 1147148138Sume if (sc->tz_cooling_active) { 1148148138Sume acpi_tz_cpufreq_restore(sc); 1149148138Sume sc->tz_cooling_active = FALSE; 1150148138Sume } 1151148703Sume sc->tz_cooling_proc = NULL; 1152148138Sume ACPI_LOCK(thermal); 1153148703Sume sc->tz_cooling_proc_running = FALSE; 1154148138Sume ACPI_UNLOCK(thermal); 1155172836Sjulian kproc_exit(0); 1156148138Sume} 1157148138Sume 1158148138Sume/* 1159148138Sume * TODO: We ignore _PSL (list of cooling devices) since cpufreq enumerates 1160148138Sume * all CPUs for us. However, it's possible in the future _PSL will 1161148138Sume * reference non-CPU devices so we may want to support it then. 1162148138Sume */ 1163148138Sumestatic int 1164148138Sumeacpi_tz_cooling_is_available(struct acpi_tz_softc *sc) 1165148138Sume{ 1166148138Sume return (sc->tz_zone.tc1 != -1 && sc->tz_zone.tc2 != -1 && 1167148138Sume sc->tz_zone.tsp != -1 && sc->tz_zone.tsp != 0 && 1168148138Sume sc->tz_zone.psv != -1); 1169148138Sume} 1170148138Sume 1171148138Sumestatic int 1172148138Sumeacpi_tz_cooling_thread_start(struct acpi_tz_softc *sc) 1173148138Sume{ 1174148138Sume int error; 1175148138Sume 1176148703Sume ACPI_LOCK(thermal); 1177148703Sume if (sc->tz_cooling_proc_running) { 1178148703Sume ACPI_UNLOCK(thermal); 1179148703Sume return (0); 1180148703Sume } 1181148703Sume sc->tz_cooling_proc_running = TRUE; 1182148703Sume ACPI_UNLOCK(thermal); 1183148138Sume error = 0; 1184148138Sume if (sc->tz_cooling_proc == NULL) { 1185209062Savg error = kproc_create(acpi_tz_cooling_thread, sc, 1186209062Savg &sc->tz_cooling_proc, RFHIGHPID, 0, "acpi_cooling%d", 1187148138Sume device_get_unit(sc->tz_dev)); 1188148703Sume if (error != 0) { 1189148138Sume device_printf(sc->tz_dev, "could not create thread - %d", error); 1190148703Sume ACPI_LOCK(thermal); 1191148703Sume sc->tz_cooling_proc_running = FALSE; 1192148703Sume ACPI_UNLOCK(thermal); 1193148703Sume } 1194148138Sume } 1195148138Sume return (error); 1196148138Sume} 1197