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: releng/10.3/sys/dev/acpica/acpi_thermal.c 255077 2013-08-30 19:21:12Z dumbbell $"); 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> 3991126Smsmith#include <sys/proc.h> 40128991Snjl#include <sys/reboot.h> 4179283Smsmith#include <sys/sysctl.h> 4291126Smsmith#include <sys/unistd.h> 4391640Siwasaki#include <sys/power.h> 4467761Smsmith 45148138Sume#include "cpufreq_if.h" 46148138Sume 47193530Sjkim#include <contrib/dev/acpica/include/acpi.h> 48193530Sjkim#include <contrib/dev/acpica/include/accommon.h> 49193530Sjkim 5067761Smsmith#include <dev/acpica/acpivar.h> 5167761Smsmith 52119529Snjl/* Hooks for the ACPI CA debugging infrastructure */ 5378999Smsmith#define _COMPONENT ACPI_THERMAL 5491126SmsmithACPI_MODULE_NAME("THERMAL") 5569744Smsmith 5671874Smsmith#define TZ_ZEROC 2732 57160657Snjl#define TZ_KELVTOC(x) (((x) - TZ_ZEROC) / 10), abs(((x) - TZ_ZEROC) % 10) 5867761Smsmith 59125366Snjl#define TZ_NOTIFY_TEMPERATURE 0x80 /* Temperature changed. */ 60125366Snjl#define TZ_NOTIFY_LEVELS 0x81 /* Cooling levels changed. */ 61125366Snjl#define TZ_NOTIFY_DEVICES 0x82 /* Device lists changed. */ 62125366Snjl#define TZ_NOTIFY_CRITICAL 0xcc /* Fake notify that _CRT/_HOT reached. */ 6378915Smsmith 64125335Snjl/* Check for temperature changes every 10 seconds by default */ 65125335Snjl#define TZ_POLLRATE 10 6678915Smsmith 67125335Snjl/* Make sure the reported temperature is valid for this number of polls. */ 68125335Snjl#define TZ_VALIDCHECKS 3 69125335Snjl 70125366Snjl/* Notify the user we will be shutting down in one more poll cycle. */ 71125366Snjl#define TZ_NOTIFYCOUNT (TZ_VALIDCHECKS - 1) 72125366Snjl 73119529Snjl/* ACPI spec defines this */ 74119529Snjl#define TZ_NUMLEVELS 10 7579375Smsmithstruct acpi_tz_zone { 7678915Smsmith int ac[TZ_NUMLEVELS]; 7778915Smsmith ACPI_BUFFER al[TZ_NUMLEVELS]; 7878915Smsmith int crt; 7978915Smsmith int hot; 8078915Smsmith ACPI_BUFFER psl; 8178915Smsmith int psv; 8278915Smsmith int tc1; 8378915Smsmith int tc2; 8478915Smsmith int tsp; 8578915Smsmith int tzp; 8678915Smsmith}; 8778915Smsmith 8867761Smsmithstruct acpi_tz_softc { 89119529Snjl device_t tz_dev; 90119529Snjl ACPI_HANDLE tz_handle; /*Thermal zone handle*/ 91119529Snjl int tz_temperature; /*Current temperature*/ 92119529Snjl int tz_active; /*Current active cooling*/ 9379375Smsmith#define TZ_ACTIVE_NONE -1 94178506Srpaulo#define TZ_ACTIVE_UNKNOWN -2 95119529Snjl int tz_requested; /*Minimum active cooling*/ 96119529Snjl int tz_thflags; /*Current temp-related flags*/ 9779375Smsmith#define TZ_THFLAG_NONE 0 9879375Smsmith#define TZ_THFLAG_PSV (1<<0) 9979375Smsmith#define TZ_THFLAG_HOT (1<<2) 100148138Sume#define TZ_THFLAG_CRT (1<<3) 10179283Smsmith int tz_flags; 102119529Snjl#define TZ_FLAG_NO_SCP (1<<0) /*No _SCP method*/ 103119529Snjl#define TZ_FLAG_GETPROFILE (1<<1) /*Get power_profile in timeout*/ 104133624Snjl#define TZ_FLAG_GETSETTINGS (1<<2) /*Get devs/setpoints*/ 105119529Snjl struct timespec tz_cooling_started; 106119529Snjl /*Current cooling starting time*/ 10779283Smsmith 108119529Snjl struct sysctl_ctx_list tz_sysctl_ctx; 10979283Smsmith struct sysctl_oid *tz_sysctl_tree; 110133624Snjl eventhandler_tag tz_event; 111133624Snjl 112119529Snjl struct acpi_tz_zone tz_zone; /*Thermal zone parameters*/ 113125335Snjl int tz_validchecks; 114255077Sdumbbell int tz_insane_tmp_notified; 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 125241538Savg#define TZ_ACTIVE_LEVEL(act) ((act) >= 0 ? (act) : TZ_NUMLEVELS) 126241538Savg 127148138Sume#define CPUFREQ_MAX_LEVELS 64 /* XXX cpufreq should export this */ 128148138Sume 12967761Smsmithstatic int acpi_tz_probe(device_t dev); 13067761Smsmithstatic int acpi_tz_attach(device_t dev); 13178915Smsmithstatic int acpi_tz_establish(struct acpi_tz_softc *sc); 132119529Snjlstatic void acpi_tz_monitor(void *Context); 13378915Smsmithstatic void acpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg); 13478915Smsmithstatic void acpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg); 135119529Snjlstatic void acpi_tz_getparam(struct acpi_tz_softc *sc, char *node, 136119529Snjl int *data); 13779283Smsmithstatic void acpi_tz_sanity(struct acpi_tz_softc *sc, int *val, char *what); 13879375Smsmithstatic int acpi_tz_active_sysctl(SYSCTL_HANDLER_ARGS); 139148138Sumestatic int acpi_tz_cooling_sysctl(SYSCTL_HANDLER_ARGS); 140160657Snjlstatic int acpi_tz_temp_sysctl(SYSCTL_HANDLER_ARGS); 141174889Sumestatic int acpi_tz_passive_sysctl(SYSCTL_HANDLER_ARGS); 142119529Snjlstatic void acpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, 143119529Snjl void *context); 144133624Snjlstatic void acpi_tz_signal(struct acpi_tz_softc *sc, int flags); 145133624Snjlstatic void acpi_tz_timeout(struct acpi_tz_softc *sc, int flags); 14691640Siwasakistatic void acpi_tz_power_profile(void *arg); 14791126Smsmithstatic void acpi_tz_thread(void *arg); 148148138Sumestatic int acpi_tz_cooling_is_available(struct acpi_tz_softc *sc); 149148138Sumestatic int acpi_tz_cooling_thread_start(struct acpi_tz_softc *sc); 15091126Smsmith 15167761Smsmithstatic device_method_t acpi_tz_methods[] = { 15267761Smsmith /* Device interface */ 15367761Smsmith DEVMETHOD(device_probe, acpi_tz_probe), 15467761Smsmith DEVMETHOD(device_attach, acpi_tz_attach), 15567761Smsmith 156246128Ssbz DEVMETHOD_END 15767761Smsmith}; 15867761Smsmith 15967761Smsmithstatic driver_t acpi_tz_driver = { 16067761Smsmith "acpi_tz", 16167761Smsmith acpi_tz_methods, 16267761Smsmith sizeof(struct acpi_tz_softc), 16367761Smsmith}; 16467761Smsmith 165255077Sdumbbellstatic char *acpi_tz_tmp_name = "_TMP"; 166255077Sdumbbell 16789054Smsmithstatic devclass_t acpi_tz_devclass; 16867761SmsmithDRIVER_MODULE(acpi_tz, acpi, acpi_tz_driver, acpi_tz_devclass, 0, 0); 169128071SnjlMODULE_DEPEND(acpi_tz, acpi, 1, 1, 1); 17067761Smsmith 17179283Smsmithstatic struct sysctl_ctx_list acpi_tz_sysctl_ctx; 17279283Smsmithstatic struct sysctl_oid *acpi_tz_sysctl_tree; 17379283Smsmith 174119529Snjl/* Minimum cooling run time */ 175160657Snjlstatic int acpi_tz_min_runtime; 17688420Siwasakistatic int acpi_tz_polling_rate = TZ_POLLRATE; 177160657Snjlstatic int acpi_tz_override; 17885699Siwasaki 179119529Snjl/* Timezone polling thread */ 180119529Snjlstatic struct proc *acpi_tz_proc; 181133624SnjlACPI_LOCK_DECL(thermal, "ACPI thermal zone"); 182119529Snjl 183176329Sumestatic int acpi_tz_cooling_unit = -1; 184176329Sume 18567761Smsmithstatic int 18667761Smsmithacpi_tz_probe(device_t dev) 18767761Smsmith{ 18878999Smsmith int result; 189148138Sume 190119529Snjl if (acpi_get_type(dev) == ACPI_TYPE_THERMAL && !acpi_disabled("thermal")) { 191120453Snjl device_set_desc(dev, "Thermal Zone"); 19278999Smsmith result = -10; 193133624Snjl } else 19478999Smsmith result = ENXIO; 195119529Snjl return (result); 19667761Smsmith} 19767761Smsmith 19867761Smsmithstatic int 19967761Smsmithacpi_tz_attach(device_t dev) 20067761Smsmith{ 20167761Smsmith struct acpi_tz_softc *sc; 20279283Smsmith struct acpi_softc *acpi_sc; 20378915Smsmith int error; 20479283Smsmith char oidname[8]; 20567761Smsmith 20696926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 20769744Smsmith 20867761Smsmith sc = device_get_softc(dev); 20967761Smsmith sc->tz_dev = dev; 21067761Smsmith sc->tz_handle = acpi_get_handle(dev); 21179375Smsmith sc->tz_requested = TZ_ACTIVE_NONE; 212178506Srpaulo sc->tz_active = TZ_ACTIVE_UNKNOWN; 213135548Snjl sc->tz_thflags = TZ_THFLAG_NONE; 214148138Sume sc->tz_cooling_proc = NULL; 215148703Sume sc->tz_cooling_proc_running = FALSE; 216148138Sume sc->tz_cooling_active = FALSE; 217148138Sume sc->tz_cooling_updated = FALSE; 218176329Sume sc->tz_cooling_enabled = FALSE; 21967761Smsmith 22078915Smsmith /* 22178915Smsmith * Parse the current state of the thermal zone and build control 222133624Snjl * structures. We don't need to worry about interference with the 223133624Snjl * control thread since we haven't fully attached this device yet. 22478915Smsmith */ 22578915Smsmith if ((error = acpi_tz_establish(sc)) != 0) 226133624Snjl return (error); 227133624Snjl 22878915Smsmith /* 22978915Smsmith * Register for any Notify events sent to this zone. 23078915Smsmith */ 231148138Sume AcpiInstallNotifyHandler(sc->tz_handle, ACPI_DEVICE_NOTIFY, 23278999Smsmith acpi_tz_notify_handler, sc); 23370271Stakawata 23471874Smsmith /* 23579283Smsmith * Create our sysctl nodes. 23679283Smsmith * 23779283Smsmith * XXX we need a mechanism for adding nodes under ACPI. 23879283Smsmith */ 23979283Smsmith if (device_get_unit(dev) == 0) { 24079283Smsmith acpi_sc = acpi_device_get_parent_softc(dev); 24179283Smsmith sysctl_ctx_init(&acpi_tz_sysctl_ctx); 24279283Smsmith acpi_tz_sysctl_tree = SYSCTL_ADD_NODE(&acpi_tz_sysctl_ctx, 243119529Snjl SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), 244119529Snjl OID_AUTO, "thermal", CTLFLAG_RD, 0, ""); 24585699Siwasaki SYSCTL_ADD_INT(&acpi_tz_sysctl_ctx, 24685699Siwasaki SYSCTL_CHILDREN(acpi_tz_sysctl_tree), 247159476Snjl OID_AUTO, "min_runtime", CTLFLAG_RW, 248119529Snjl &acpi_tz_min_runtime, 0, 249119529Snjl "minimum cooling run time in sec"); 25088420Siwasaki SYSCTL_ADD_INT(&acpi_tz_sysctl_ctx, 25188420Siwasaki SYSCTL_CHILDREN(acpi_tz_sysctl_tree), 252159476Snjl OID_AUTO, "polling_rate", CTLFLAG_RW, 253227642Seadler &acpi_tz_polling_rate, 0, "monitor polling interval in seconds"); 254160657Snjl SYSCTL_ADD_INT(&acpi_tz_sysctl_ctx, 255160657Snjl SYSCTL_CHILDREN(acpi_tz_sysctl_tree), OID_AUTO, 256160657Snjl "user_override", CTLFLAG_RW, &acpi_tz_override, 0, 257160657Snjl "allow override of thermal settings"); 25879283Smsmith } 25979283Smsmith sysctl_ctx_init(&sc->tz_sysctl_ctx); 26079283Smsmith sprintf(oidname, "tz%d", device_get_unit(dev)); 26179283Smsmith sc->tz_sysctl_tree = SYSCTL_ADD_NODE(&sc->tz_sysctl_ctx, 262119529Snjl SYSCTL_CHILDREN(acpi_tz_sysctl_tree), 263119529Snjl OID_AUTO, oidname, CTLFLAG_RD, 0, ""); 26479375Smsmith SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 265220798Smdf OID_AUTO, "temperature", CTLTYPE_INT | CTLFLAG_RD, 266220798Smdf &sc->tz_temperature, 0, sysctl_handle_int, 267220798Smdf "IK", "current thermal zone temperature"); 268220798Smdf SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 26979375Smsmith OID_AUTO, "active", CTLTYPE_INT | CTLFLAG_RW, 270160657Snjl sc, 0, acpi_tz_active_sysctl, "I", "cooling is active"); 271148138Sume SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 272148138Sume OID_AUTO, "passive_cooling", CTLTYPE_INT | CTLFLAG_RW, 273160657Snjl sc, 0, acpi_tz_cooling_sysctl, "I", 274160657Snjl "enable passive (speed reduction) cooling"); 275148138Sume 27679283Smsmith SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 27779375Smsmith OID_AUTO, "thermal_flags", CTLFLAG_RD, 27879375Smsmith &sc->tz_thflags, 0, "thermal zone flags"); 279160657Snjl SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 280160657Snjl OID_AUTO, "_PSV", CTLTYPE_INT | CTLFLAG_RW, 281160657Snjl sc, offsetof(struct acpi_tz_softc, tz_zone.psv), 282160657Snjl acpi_tz_temp_sysctl, "IK", "passive cooling temp setpoint"); 283160657Snjl SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 284160657Snjl OID_AUTO, "_HOT", CTLTYPE_INT | CTLFLAG_RW, 285160657Snjl sc, offsetof(struct acpi_tz_softc, tz_zone.hot), 286160657Snjl acpi_tz_temp_sysctl, "IK", 287160657Snjl "too hot temp setpoint (suspend now)"); 288160657Snjl SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 289160657Snjl OID_AUTO, "_CRT", CTLTYPE_INT | CTLFLAG_RW, 290160657Snjl sc, offsetof(struct acpi_tz_softc, tz_zone.crt), 291160657Snjl acpi_tz_temp_sysctl, "IK", 292160657Snjl "critical temp setpoint (shutdown now)"); 293174889Sume SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 294220798Smdf OID_AUTO, "_ACx", CTLTYPE_INT | CTLFLAG_RD, 295220871Smdf &sc->tz_zone.ac, sizeof(sc->tz_zone.ac), 296220871Smdf sysctl_handle_opaque, "IK", ""); 297220798Smdf SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 298174889Sume OID_AUTO, "_TC1", CTLTYPE_INT | CTLFLAG_RW, 299174889Sume sc, offsetof(struct acpi_tz_softc, tz_zone.tc1), 300174889Sume acpi_tz_passive_sysctl, "I", 301174889Sume "thermal constant 1 for passive cooling"); 302174889Sume SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 303174889Sume OID_AUTO, "_TC2", CTLTYPE_INT | CTLFLAG_RW, 304174889Sume sc, offsetof(struct acpi_tz_softc, tz_zone.tc2), 305174889Sume acpi_tz_passive_sysctl, "I", 306174889Sume "thermal constant 2 for passive cooling"); 307174889Sume SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 308174889Sume OID_AUTO, "_TSP", CTLTYPE_INT | CTLFLAG_RW, 309174889Sume sc, offsetof(struct acpi_tz_softc, tz_zone.tsp), 310174889Sume acpi_tz_passive_sysctl, "I", 311174889Sume "thermal sampling period for passive cooling"); 31279283Smsmith 31379283Smsmith /* 314148138Sume * Create thread to service all of the thermal zones. Register 315148138Sume * our power profile event handler. 31679375Smsmith */ 317133624Snjl sc->tz_event = EVENTHANDLER_REGISTER(power_profile_change, 318133624Snjl acpi_tz_power_profile, sc, 0); 319133624Snjl if (acpi_tz_proc == NULL) { 320172836Sjulian error = kproc_create(acpi_tz_thread, NULL, &acpi_tz_proc, 321133624Snjl RFHIGHPID, 0, "acpi_thermal"); 322133624Snjl if (error != 0) { 323133624Snjl device_printf(sc->tz_dev, "could not create thread - %d", error); 324133624Snjl goto out; 325133624Snjl } 326133624Snjl } 32779375Smsmith 328176329Sume /* 329176329Sume * Create a thread to handle passive cooling for 1st zone which 330176329Sume * has _PSV, _TSP, _TC1 and _TC2. Users can enable it for other 331176329Sume * zones manually for now. 332176329Sume * 333176329Sume * XXX We enable only one zone to avoid multiple zones conflict 334176329Sume * with each other since cpufreq currently sets all CPUs to the 335176329Sume * given frequency whereas it's possible for different thermal 336176329Sume * zones to specify independent settings for multiple CPUs. 337176329Sume */ 338176329Sume if (acpi_tz_cooling_unit < 0 && acpi_tz_cooling_is_available(sc)) 339176329Sume sc->tz_cooling_enabled = TRUE; 340148138Sume if (sc->tz_cooling_enabled) { 341176329Sume error = acpi_tz_cooling_thread_start(sc); 342176329Sume if (error != 0) { 343148138Sume sc->tz_cooling_enabled = FALSE; 344176329Sume goto out; 345176329Sume } 346176329Sume acpi_tz_cooling_unit = device_get_unit(dev); 347148138Sume } 348148138Sume 34979375Smsmith /* 350133624Snjl * Flag the event handler for a manual invocation by our timeout. 351133624Snjl * We defer it like this so that the rest of the subsystem has time 352133624Snjl * to come up. Don't bother evaluating/printing the temperature at 353133624Snjl * this point; on many systems it'll be bogus until the EC is running. 35471874Smsmith */ 355133624Snjl sc->tz_flags |= TZ_FLAG_GETPROFILE; 35678999Smsmith 357133624Snjlout: 358133624Snjl if (error != 0) { 359133624Snjl EVENTHANDLER_DEREGISTER(power_profile_change, sc->tz_event); 360133624Snjl AcpiRemoveNotifyHandler(sc->tz_handle, ACPI_DEVICE_NOTIFY, 361133624Snjl acpi_tz_notify_handler); 362133624Snjl sysctl_ctx_free(&sc->tz_sysctl_ctx); 36391126Smsmith } 364119529Snjl return_VALUE (error); 36567761Smsmith} 36670271Stakawata 36778915Smsmith/* 36878915Smsmith * Parse the current state of this thermal zone and set up to use it. 36978915Smsmith * 37078915Smsmith * Note that we may have previous state, which will have to be discarded. 37178915Smsmith */ 37278915Smsmithstatic int 37378915Smsmithacpi_tz_establish(struct acpi_tz_softc *sc) 37478915Smsmith{ 37578915Smsmith ACPI_OBJECT *obj; 37678915Smsmith int i; 37778915Smsmith char nbuf[8]; 378148138Sume 37996926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 38078915Smsmith 381134909Snjl /* Erase any existing state. */ 38278915Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) 38379375Smsmith if (sc->tz_zone.al[i].Pointer != NULL) 38479375Smsmith AcpiOsFree(sc->tz_zone.al[i].Pointer); 38579375Smsmith if (sc->tz_zone.psl.Pointer != NULL) 38679375Smsmith AcpiOsFree(sc->tz_zone.psl.Pointer); 38778915Smsmith 388149449Sume /* 389149449Sume * XXX: We initialize only ACPI_BUFFER to avoid race condition 390149449Sume * with passive cooling thread which refers psv, tc1, tc2 and tsp. 391149449Sume */ 392149449Sume bzero(sc->tz_zone.ac, sizeof(sc->tz_zone.ac)); 393149449Sume bzero(sc->tz_zone.al, sizeof(sc->tz_zone.al)); 394149449Sume bzero(&sc->tz_zone.psl, sizeof(sc->tz_zone.psl)); 395149449Sume 396119529Snjl /* Evaluate thermal zone parameters. */ 39778915Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) { 39878915Smsmith sprintf(nbuf, "_AC%d", i); 39979375Smsmith acpi_tz_getparam(sc, nbuf, &sc->tz_zone.ac[i]); 40078915Smsmith sprintf(nbuf, "_AL%d", i); 40191126Smsmith sc->tz_zone.al[i].Length = ACPI_ALLOCATE_BUFFER; 40291126Smsmith sc->tz_zone.al[i].Pointer = NULL; 40391126Smsmith AcpiEvaluateObject(sc->tz_handle, nbuf, NULL, &sc->tz_zone.al[i]); 40479375Smsmith obj = (ACPI_OBJECT *)sc->tz_zone.al[i].Pointer; 40578915Smsmith if (obj != NULL) { 406119529Snjl /* Should be a package containing a list of power objects */ 40778915Smsmith if (obj->Type != ACPI_TYPE_PACKAGE) { 408119529Snjl device_printf(sc->tz_dev, "%s has unknown type %d, rejecting\n", 40978915Smsmith nbuf, obj->Type); 410119529Snjl return_VALUE (ENXIO); 41178915Smsmith } 41278915Smsmith } 41378915Smsmith } 41479375Smsmith acpi_tz_getparam(sc, "_CRT", &sc->tz_zone.crt); 41579375Smsmith acpi_tz_getparam(sc, "_HOT", &sc->tz_zone.hot); 41691126Smsmith sc->tz_zone.psl.Length = ACPI_ALLOCATE_BUFFER; 41791126Smsmith sc->tz_zone.psl.Pointer = NULL; 41891126Smsmith AcpiEvaluateObject(sc->tz_handle, "_PSL", NULL, &sc->tz_zone.psl); 41979375Smsmith acpi_tz_getparam(sc, "_PSV", &sc->tz_zone.psv); 42079375Smsmith acpi_tz_getparam(sc, "_TC1", &sc->tz_zone.tc1); 42179375Smsmith acpi_tz_getparam(sc, "_TC2", &sc->tz_zone.tc2); 42279375Smsmith acpi_tz_getparam(sc, "_TSP", &sc->tz_zone.tsp); 42379375Smsmith acpi_tz_getparam(sc, "_TZP", &sc->tz_zone.tzp); 42478915Smsmith 42578915Smsmith /* 42679283Smsmith * Sanity-check the values we've been given. 42779283Smsmith * 42879283Smsmith * XXX what do we do about systems that give us the same value for 42979283Smsmith * more than one of these setpoints? 43079283Smsmith */ 43179375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.crt, "_CRT"); 43279375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.hot, "_HOT"); 43379375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.psv, "_PSV"); 43479283Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) 43579375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.ac[i], "_ACx"); 43679283Smsmith 437119529Snjl return_VALUE (0); 43878915Smsmith} 43978915Smsmith 440133624Snjlstatic char *aclevel_string[] = { 441133624Snjl "NONE", "_AC0", "_AC1", "_AC2", "_AC3", "_AC4", 442133624Snjl "_AC5", "_AC6", "_AC7", "_AC8", "_AC9" 443133624Snjl}; 44485699Siwasaki 44585699Siwasakistatic __inline const char * 44685699Siwasakiacpi_tz_aclevel_string(int active) 44785699Siwasaki{ 448133624Snjl if (active < -1 || active >= TZ_NUMLEVELS) 449133624Snjl return (aclevel_string[0]); 45085699Siwasaki 451133624Snjl return (aclevel_string[active + 1]); 45285699Siwasaki} 45385699Siwasaki 45478915Smsmith/* 455149450Sume * Get the current temperature. 456149450Sume */ 457149450Sumestatic int 458149450Sumeacpi_tz_get_temperature(struct acpi_tz_softc *sc) 459149450Sume{ 460149450Sume int temp; 461149450Sume ACPI_STATUS status; 462149450Sume 463149482Skan ACPI_FUNCTION_NAME ("acpi_tz_get_temperature"); 464149482Skan 465167249Snjl /* Evaluate the thermal zone's _TMP method. */ 466255077Sdumbbell status = acpi_GetInteger(sc->tz_handle, acpi_tz_tmp_name, &temp); 467149450Sume if (ACPI_FAILURE(status)) { 468149450Sume ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 469149450Sume "error fetching current temperature -- %s\n", 470149450Sume AcpiFormatException(status)); 471149450Sume return (FALSE); 472149450Sume } 473149450Sume 474167249Snjl /* Check it for validity. */ 475255077Sdumbbell acpi_tz_sanity(sc, &temp, acpi_tz_tmp_name); 476167249Snjl if (temp == -1) 477167249Snjl return (FALSE); 478167249Snjl 479149450Sume ACPI_DEBUG_PRINT((ACPI_DB_VALUES, "got %d.%dC\n", TZ_KELVTOC(temp))); 480149450Sume sc->tz_temperature = temp; 481149450Sume return (TRUE); 482149450Sume} 483149450Sume 484149450Sume/* 48578915Smsmith * Evaluate the condition of a thermal zone, take appropriate actions. 48678915Smsmith */ 48771874Smsmithstatic void 488119529Snjlacpi_tz_monitor(void *Context) 48971874Smsmith{ 490119529Snjl struct acpi_tz_softc *sc; 491119529Snjl struct timespec curtime; 49279283Smsmith int temp; 49378915Smsmith int i; 49479283Smsmith int newactive, newflags; 49570271Stakawata 49696926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 49770271Stakawata 498119529Snjl sc = (struct acpi_tz_softc *)Context; 49988420Siwasaki 500119529Snjl /* Get the current temperature. */ 501149450Sume if (!acpi_tz_get_temperature(sc)) { 50278915Smsmith /* XXX disable zone? go to max cooling? */ 503133624Snjl return_VOID; 50471874Smsmith } 505149450Sume temp = sc->tz_temperature; 50688420Siwasaki 50778915Smsmith /* 50878915Smsmith * Work out what we ought to be doing right now. 50979283Smsmith * 51079283Smsmith * Note that the _ACx levels sort from hot to cold. 51178915Smsmith */ 51279283Smsmith newactive = TZ_ACTIVE_NONE; 51379375Smsmith for (i = TZ_NUMLEVELS - 1; i >= 0; i--) { 514245266Smav if (sc->tz_zone.ac[i] != -1 && temp >= sc->tz_zone.ac[i]) 51579283Smsmith newactive = i; 51679375Smsmith } 51779283Smsmith 51885699Siwasaki /* 51985699Siwasaki * We are going to get _ACx level down (colder side), but give a guaranteed 52085699Siwasaki * minimum cooling run time if requested. 52185699Siwasaki */ 52285699Siwasaki if (acpi_tz_min_runtime > 0 && sc->tz_active != TZ_ACTIVE_NONE && 523178506Srpaulo sc->tz_active != TZ_ACTIVE_UNKNOWN && 52485699Siwasaki (newactive == TZ_ACTIVE_NONE || newactive > sc->tz_active)) { 525119529Snjl 52685699Siwasaki getnanotime(&curtime); 52785699Siwasaki timespecsub(&curtime, &sc->tz_cooling_started); 528119529Snjl if (curtime.tv_sec < acpi_tz_min_runtime) 52985699Siwasaki newactive = sc->tz_active; 53085699Siwasaki } 53185699Siwasaki 532119529Snjl /* Handle user override of active mode */ 533176327Srpaulo if (sc->tz_requested != TZ_ACTIVE_NONE && (newactive == TZ_ACTIVE_NONE 534176327Srpaulo || sc->tz_requested < newactive)) 53579375Smsmith newactive = sc->tz_requested; 53678915Smsmith 53779375Smsmith /* update temperature-related flags */ 53879375Smsmith newflags = TZ_THFLAG_NONE; 539124439Snjl if (sc->tz_zone.psv != -1 && temp >= sc->tz_zone.psv) 54079375Smsmith newflags |= TZ_THFLAG_PSV; 541124439Snjl if (sc->tz_zone.hot != -1 && temp >= sc->tz_zone.hot) 54279375Smsmith newflags |= TZ_THFLAG_HOT; 543124439Snjl if (sc->tz_zone.crt != -1 && temp >= sc->tz_zone.crt) 54479375Smsmith newflags |= TZ_THFLAG_CRT; 54579375Smsmith 546119529Snjl /* If the active cooling state has changed, we have to switch things. */ 547178506Srpaulo if (sc->tz_active == TZ_ACTIVE_UNKNOWN) { 548178506Srpaulo /* 549178506Srpaulo * We don't know which cooling device is on or off, 550178506Srpaulo * so stop them all, because we now know which 551178506Srpaulo * should be on (if any). 552178506Srpaulo */ 553178506Srpaulo for (i = 0; i < TZ_NUMLEVELS; i++) { 554178506Srpaulo if (sc->tz_zone.al[i].Pointer != NULL) { 555178506Srpaulo acpi_ForeachPackageObject( 556178506Srpaulo (ACPI_OBJECT *)sc->tz_zone.al[i].Pointer, 557178506Srpaulo acpi_tz_switch_cooler_off, sc); 558178506Srpaulo } 559178506Srpaulo } 560178506Srpaulo /* now we know that all devices are off */ 561178506Srpaulo sc->tz_active = TZ_ACTIVE_NONE; 562178506Srpaulo } 563178506Srpaulo 56479283Smsmith if (newactive != sc->tz_active) { 565241538Savg /* Turn off unneeded cooling devices that are on, if any are */ 566241538Savg for (i = TZ_ACTIVE_LEVEL(sc->tz_active); 567241538Savg i < TZ_ACTIVE_LEVEL(newactive); i++) { 568119529Snjl acpi_ForeachPackageObject( 569241538Savg (ACPI_OBJECT *)sc->tz_zone.al[i].Pointer, 570119529Snjl acpi_tz_switch_cooler_off, sc); 571241538Savg } 572119529Snjl /* Turn on cooling devices that are required, if any are */ 573241538Savg for (i = TZ_ACTIVE_LEVEL(sc->tz_active) - 1; 574241538Savg i >= TZ_ACTIVE_LEVEL(newactive); i--) { 575119529Snjl acpi_ForeachPackageObject( 576241538Savg (ACPI_OBJECT *)sc->tz_zone.al[i].Pointer, 577119529Snjl acpi_tz_switch_cooler_on, sc); 578119529Snjl } 579241538Savg 58086552Siwasaki ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 581119529Snjl "switched from %s to %s: %d.%dC\n", 582119529Snjl acpi_tz_aclevel_string(sc->tz_active), 583119529Snjl acpi_tz_aclevel_string(newactive), TZ_KELVTOC(temp)); 58479283Smsmith sc->tz_active = newactive; 585142195Snjl getnanotime(&sc->tz_cooling_started); 58679283Smsmith } 58778915Smsmith 588119529Snjl /* XXX (de)activate any passive cooling that may be required. */ 58978915Smsmith 59078915Smsmith /* 591125335Snjl * If the temperature is at _HOT or _CRT, increment our event count. 592125335Snjl * If it has occurred enough times, shutdown the system. This is 593125335Snjl * needed because some systems will report an invalid high temperature 594125335Snjl * for one poll cycle. It is suspected this is due to the embedded 595125335Snjl * controller timing out. A typical value is 138C for one cycle on 596125335Snjl * a system that is otherwise 65C. 597125366Snjl * 598125366Snjl * If we're almost at that threshold, notify the user through devd(8). 59978915Smsmith */ 600125335Snjl if ((newflags & (TZ_THFLAG_HOT | TZ_THFLAG_CRT)) != 0) { 601125366Snjl sc->tz_validchecks++; 602125366Snjl if (sc->tz_validchecks == TZ_VALIDCHECKS) { 603125335Snjl device_printf(sc->tz_dev, 604125335Snjl "WARNING - current temperature (%d.%dC) exceeds safe limits\n", 605125335Snjl TZ_KELVTOC(sc->tz_temperature)); 606125335Snjl shutdown_nice(RB_POWEROFF); 607125366Snjl } else if (sc->tz_validchecks == TZ_NOTIFYCOUNT) 608125366Snjl acpi_UserNotify("Thermal", sc->tz_handle, TZ_NOTIFY_CRITICAL); 609125335Snjl } else { 610125335Snjl sc->tz_validchecks = 0; 61178915Smsmith } 61279375Smsmith sc->tz_thflags = newflags; 61378915Smsmith 61471874Smsmith return_VOID; 61571874Smsmith} 61670271Stakawata 61778915Smsmith/* 618148138Sume * Given an object, verify that it's a reference to a device of some sort, 61978915Smsmith * and try to switch it off. 62078915Smsmith */ 62178915Smsmithstatic void 62278915Smsmithacpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg) 62378915Smsmith{ 624128047Snjl ACPI_HANDLE cooler; 62578915Smsmith 62696926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 62778915Smsmith 628128047Snjl cooler = acpi_GetReference(NULL, obj); 629128047Snjl if (cooler == NULL) { 630128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get handle\n")); 631128047Snjl return_VOID; 632128047Snjl } 633102470Siwasaki 634128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s off\n", 635128047Snjl acpi_name(cooler))); 636128150Snjl acpi_pwr_switch_consumer(cooler, ACPI_STATE_D3); 637119529Snjl 63879375Smsmith return_VOID; 63978915Smsmith} 64078915Smsmith 64178915Smsmith/* 642148138Sume * Given an object, verify that it's a reference to a device of some sort, 64378915Smsmith * and try to switch it on. 64478915Smsmith * 645128047Snjl * XXX replication of off/on function code is bad. 64678915Smsmith */ 64778915Smsmithstatic void 64878915Smsmithacpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg) 64978915Smsmith{ 65078915Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg; 65178999Smsmith ACPI_HANDLE cooler; 65279375Smsmith ACPI_STATUS status; 653148138Sume 65496926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 65578915Smsmith 656128047Snjl cooler = acpi_GetReference(NULL, obj); 657128047Snjl if (cooler == NULL) { 658128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get handle\n")); 659128047Snjl return_VOID; 660128047Snjl } 661102470Siwasaki 662128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s on\n", 663128047Snjl acpi_name(cooler))); 664128047Snjl status = acpi_pwr_switch_consumer(cooler, ACPI_STATE_D0); 665128047Snjl if (ACPI_FAILURE(status)) { 666128047Snjl ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 667128047Snjl "failed to activate %s - %s\n", acpi_name(cooler), 668128047Snjl AcpiFormatException(status)); 66978915Smsmith } 670119529Snjl 671119529Snjl return_VOID; 67278915Smsmith} 67378915Smsmith 67478915Smsmith/* 67578915Smsmith * Read/debug-print a parameter, default it to -1. 67678915Smsmith */ 67778915Smsmithstatic void 67878915Smsmithacpi_tz_getparam(struct acpi_tz_softc *sc, char *node, int *data) 67978915Smsmith{ 68078915Smsmith 68196926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 68278915Smsmith 683126560Snjl if (ACPI_FAILURE(acpi_GetInteger(sc->tz_handle, node, data))) { 68478915Smsmith *data = -1; 68578915Smsmith } else { 686119529Snjl ACPI_DEBUG_PRINT((ACPI_DB_VALUES, "%s.%s = %d\n", 687119529Snjl acpi_name(sc->tz_handle), node, *data)); 68878915Smsmith } 689119529Snjl 690148138Sume return_VOID; 69178915Smsmith} 69279283Smsmith 69379283Smsmith/* 69479283Smsmith * Sanity-check a temperature value. Assume that setpoints 695167249Snjl * should be between 0C and 200C. 69679283Smsmith */ 69779283Smsmithstatic void 69879283Smsmithacpi_tz_sanity(struct acpi_tz_softc *sc, int *val, char *what) 69979283Smsmith{ 700167249Snjl if (*val != -1 && (*val < TZ_ZEROC || *val > TZ_ZEROC + 2000)) { 701255077Sdumbbell /* 702255077Sdumbbell * If the value we are checking is _TMP, warn the user only 703255077Sdumbbell * once. This avoids spamming messages if, for instance, the 704255077Sdumbbell * sensor is broken and always returns an invalid temperature. 705255077Sdumbbell * 706255077Sdumbbell * This is only done for _TMP; other values always emit a 707255077Sdumbbell * warning. 708255077Sdumbbell */ 709255077Sdumbbell if (what != acpi_tz_tmp_name || !sc->tz_insane_tmp_notified) { 710255077Sdumbbell device_printf(sc->tz_dev, "%s value is absurd, ignored (%d.%dC)\n", 711255077Sdumbbell what, TZ_KELVTOC(*val)); 712255077Sdumbbell 713255077Sdumbbell /* Don't warn the user again if the read value doesn't improve. */ 714255077Sdumbbell if (what == acpi_tz_tmp_name) 715255077Sdumbbell sc->tz_insane_tmp_notified = 1; 716255077Sdumbbell } 71779283Smsmith *val = -1; 718255077Sdumbbell return; 71979283Smsmith } 720255077Sdumbbell 721255077Sdumbbell /* This value is correct. Warn if it's incorrect again. */ 722255077Sdumbbell if (what == acpi_tz_tmp_name) 723255077Sdumbbell sc->tz_insane_tmp_notified = 0; 72479283Smsmith} 72579375Smsmith 72679375Smsmith/* 72779375Smsmith * Respond to a sysctl on the active state node. 728148138Sume */ 72979375Smsmithstatic int 73079375Smsmithacpi_tz_active_sysctl(SYSCTL_HANDLER_ARGS) 73179375Smsmith{ 73279375Smsmith struct acpi_tz_softc *sc; 73379375Smsmith int active; 73479375Smsmith int error; 73579375Smsmith 73679375Smsmith sc = (struct acpi_tz_softc *)oidp->oid_arg1; 73779375Smsmith active = sc->tz_active; 73879375Smsmith error = sysctl_handle_int(oidp, &active, 0, req); 73979375Smsmith 740119529Snjl /* Error or no new value */ 741119529Snjl if (error != 0 || req->newptr == NULL) 742133624Snjl return (error); 743133624Snjl if (active < -1 || active >= TZ_NUMLEVELS) 744133624Snjl return (EINVAL); 74579375Smsmith 746119529Snjl /* Set new preferred level and re-switch */ 74779375Smsmith sc->tz_requested = active; 748133624Snjl acpi_tz_signal(sc, 0); 749133624Snjl return (0); 75079375Smsmith} 75179375Smsmith 752148138Sumestatic int 753148138Sumeacpi_tz_cooling_sysctl(SYSCTL_HANDLER_ARGS) 754148138Sume{ 755148138Sume struct acpi_tz_softc *sc; 756148138Sume int enabled, error; 757148138Sume 758148138Sume sc = (struct acpi_tz_softc *)oidp->oid_arg1; 759148138Sume enabled = sc->tz_cooling_enabled; 760148138Sume error = sysctl_handle_int(oidp, &enabled, 0, req); 761148138Sume 762148138Sume /* Error or no new value */ 763148138Sume if (error != 0 || req->newptr == NULL) 764148138Sume return (error); 765148138Sume if (enabled != TRUE && enabled != FALSE) 766148138Sume return (EINVAL); 767148138Sume 768148138Sume if (enabled) { 769148138Sume if (acpi_tz_cooling_is_available(sc)) 770148138Sume error = acpi_tz_cooling_thread_start(sc); 771148138Sume else 772148138Sume error = ENODEV; 773148138Sume if (error) 774148138Sume enabled = FALSE; 775148138Sume } 776148138Sume sc->tz_cooling_enabled = enabled; 777148138Sume return (error); 778148138Sume} 779148138Sume 780160657Snjlstatic int 781160657Snjlacpi_tz_temp_sysctl(SYSCTL_HANDLER_ARGS) 782160657Snjl{ 783160657Snjl struct acpi_tz_softc *sc; 784160657Snjl int temp, *temp_ptr; 785160657Snjl int error; 786160657Snjl 787160657Snjl sc = oidp->oid_arg1; 788160657Snjl temp_ptr = (int *)((uintptr_t)sc + oidp->oid_arg2); 789160657Snjl temp = *temp_ptr; 790160657Snjl error = sysctl_handle_int(oidp, &temp, 0, req); 791160657Snjl 792160657Snjl /* Error or no new value */ 793160657Snjl if (error != 0 || req->newptr == NULL) 794160657Snjl return (error); 795160657Snjl 796160657Snjl /* Only allow changing settings if override is set. */ 797160657Snjl if (!acpi_tz_override) 798160657Snjl return (EPERM); 799160657Snjl 800160657Snjl /* Check user-supplied value for sanity. */ 801160657Snjl acpi_tz_sanity(sc, &temp, "user-supplied temp"); 802160657Snjl if (temp == -1) 803160657Snjl return (EINVAL); 804160657Snjl 805160657Snjl *temp_ptr = temp; 806160657Snjl return (0); 807160657Snjl} 808160657Snjl 809174889Sumestatic int 810174889Sumeacpi_tz_passive_sysctl(SYSCTL_HANDLER_ARGS) 811174889Sume{ 812174889Sume struct acpi_tz_softc *sc; 813174889Sume int val, *val_ptr; 814174889Sume int error; 815174889Sume 816174889Sume sc = oidp->oid_arg1; 817174889Sume val_ptr = (int *)((uintptr_t)sc + oidp->oid_arg2); 818174889Sume val = *val_ptr; 819174889Sume error = sysctl_handle_int(oidp, &val, 0, req); 820174889Sume 821174889Sume /* Error or no new value */ 822174889Sume if (error != 0 || req->newptr == NULL) 823174889Sume return (error); 824174889Sume 825174889Sume /* Only allow changing settings if override is set. */ 826174889Sume if (!acpi_tz_override) 827174889Sume return (EPERM); 828174889Sume 829174889Sume *val_ptr = val; 830174889Sume return (0); 831174889Sume} 832174889Sume 83378915Smsmithstatic void 83471874Smsmithacpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context) 83571874Smsmith{ 83678915Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)context; 83778915Smsmith 83896926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 83970271Stakawata 840133624Snjl switch (notify) { 84178915Smsmith case TZ_NOTIFY_TEMPERATURE: 842119529Snjl /* Temperature change occurred */ 843133624Snjl acpi_tz_signal(sc, 0); 84478915Smsmith break; 84578915Smsmith case TZ_NOTIFY_DEVICES: 84678915Smsmith case TZ_NOTIFY_LEVELS: 847119529Snjl /* Zone devices/setpoints changed */ 848133624Snjl acpi_tz_signal(sc, TZ_FLAG_GETSETTINGS); 84978915Smsmith break; 85078915Smsmith default: 85186552Siwasaki ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 852119529Snjl "unknown Notify event 0x%x\n", notify); 85378915Smsmith break; 85471874Smsmith } 855119529Snjl 856121493Snjl acpi_UserNotify("Thermal", h, notify); 857121493Snjl 85871874Smsmith return_VOID; 85971874Smsmith} 86070271Stakawata 861133624Snjlstatic void 862133624Snjlacpi_tz_signal(struct acpi_tz_softc *sc, int flags) 863133624Snjl{ 864133624Snjl ACPI_LOCK(thermal); 865133624Snjl sc->tz_flags |= flags; 866133624Snjl ACPI_UNLOCK(thermal); 867133624Snjl wakeup(&acpi_tz_proc); 868133624Snjl} 869133624Snjl 87078915Smsmith/* 871134909Snjl * Notifies can be generated asynchronously but have also been seen to be 872134909Snjl * triggered by other thermal methods. One system generates a notify of 873134909Snjl * 0x81 when the fan is turned on or off. Another generates it when _SCP 874134909Snjl * is called. To handle these situations, we check the zone via 875134909Snjl * acpi_tz_monitor() before evaluating changes to setpoints or the cooling 876134909Snjl * policy. 87778915Smsmith */ 87878915Smsmithstatic void 879133624Snjlacpi_tz_timeout(struct acpi_tz_softc *sc, int flags) 88078915Smsmith{ 881134909Snjl 882134909Snjl /* Check the current temperature and take action based on it */ 883134909Snjl acpi_tz_monitor(sc); 884134909Snjl 885133624Snjl /* If requested, get the power profile settings. */ 886133624Snjl if (flags & TZ_FLAG_GETPROFILE) 887133624Snjl acpi_tz_power_profile(sc); 88879375Smsmith 889134909Snjl /* 890134909Snjl * If requested, check for new devices/setpoints. After finding them, 891134909Snjl * check if we need to switch fans based on the new values. 892134909Snjl */ 893134909Snjl if (flags & TZ_FLAG_GETSETTINGS) { 894133624Snjl acpi_tz_establish(sc); 895134909Snjl acpi_tz_monitor(sc); 896134909Snjl } 89778915Smsmith 89878915Smsmith /* XXX passive cooling actions? */ 89978915Smsmith} 90079375Smsmith 90179375Smsmith/* 90279375Smsmith * System power profile may have changed; fetch and notify the 90379375Smsmith * thermal zone accordingly. 90479375Smsmith * 90579375Smsmith * Since this can be called from an arbitrary eventhandler, it needs 90679375Smsmith * to get the ACPI lock itself. 90779375Smsmith */ 90879375Smsmithstatic void 90991640Siwasakiacpi_tz_power_profile(void *arg) 91079375Smsmith{ 91179375Smsmith ACPI_STATUS status; 91279375Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg; 91391640Siwasaki int state; 91479375Smsmith 91591640Siwasaki state = power_profile_get_state(); 916119529Snjl if (state != POWER_PROFILE_PERFORMANCE && state != POWER_PROFILE_ECONOMY) 917119529Snjl return; 91891640Siwasaki 91979375Smsmith /* check that we haven't decided there's no _SCP method */ 920119529Snjl if ((sc->tz_flags & TZ_FLAG_NO_SCP) == 0) { 92179375Smsmith 922119529Snjl /* Call _SCP to set the new profile */ 923148138Sume status = acpi_SetInteger(sc->tz_handle, "_SCP", 924126560Snjl (state == POWER_PROFILE_PERFORMANCE) ? 0 : 1); 925119529Snjl if (ACPI_FAILURE(status)) { 92679385Smsmith if (status != AE_NOT_FOUND) 927119529Snjl ACPI_VPRINT(sc->tz_dev, 928119529Snjl acpi_device_get_parent_softc(sc->tz_dev), 929119529Snjl "can't evaluate %s._SCP - %s\n", 930119529Snjl acpi_name(sc->tz_handle), 931119529Snjl AcpiFormatException(status)); 93279375Smsmith sc->tz_flags |= TZ_FLAG_NO_SCP; 93379375Smsmith } else { 934119529Snjl /* We have to re-evaluate the entire zone now */ 935133624Snjl acpi_tz_signal(sc, TZ_FLAG_GETSETTINGS); 93679375Smsmith } 93779375Smsmith } 93879375Smsmith} 93979375Smsmith 94091126Smsmith/* 94191126Smsmith * Thermal zone monitor thread. 94291126Smsmith */ 94391126Smsmithstatic void 94491126Smsmithacpi_tz_thread(void *arg) 94591126Smsmith{ 94691126Smsmith device_t *devs; 94791126Smsmith int devcount, i; 948133624Snjl int flags; 949133624Snjl struct acpi_tz_softc **sc; 95091126Smsmith 95196926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 95291126Smsmith 95391126Smsmith devs = NULL; 95491126Smsmith devcount = 0; 955133624Snjl sc = NULL; 95691126Smsmith 95791126Smsmith for (;;) { 958133624Snjl /* If the number of devices has changed, re-evaluate. */ 959175014Sjhb if (devclass_get_count(acpi_tz_devclass) != devcount) { 960133624Snjl if (devs != NULL) { 961133624Snjl free(devs, M_TEMP); 962133624Snjl free(sc, M_TEMP); 963133624Snjl } 964133624Snjl devclass_get_devices(acpi_tz_devclass, &devs, &devcount); 965133624Snjl sc = malloc(sizeof(struct acpi_tz_softc *) * devcount, M_TEMP, 966133624Snjl M_WAITOK | M_ZERO); 967133624Snjl for (i = 0; i < devcount; i++) 968133624Snjl sc[i] = device_get_softc(devs[i]); 969133624Snjl } 97091126Smsmith 971133624Snjl /* Check for temperature events and act on them. */ 972133624Snjl for (i = 0; i < devcount; i++) { 973133624Snjl ACPI_LOCK(thermal); 974133624Snjl flags = sc[i]->tz_flags; 975133624Snjl sc[i]->tz_flags &= TZ_FLAG_NO_SCP; 976133624Snjl ACPI_UNLOCK(thermal); 977133624Snjl acpi_tz_timeout(sc[i], flags); 978133624Snjl } 97991215Smsmith 980133624Snjl /* If more work to do, don't go to sleep yet. */ 981133624Snjl ACPI_LOCK(thermal); 982133624Snjl for (i = 0; i < devcount; i++) { 983133624Snjl if (sc[i]->tz_flags & ~TZ_FLAG_NO_SCP) 984133624Snjl break; 985133624Snjl } 98691126Smsmith 987133624Snjl /* 988133624Snjl * If we have no more work, sleep for a while, setting PDROP so that 989133624Snjl * the mutex will not be reacquired. Otherwise, drop the mutex and 990133624Snjl * loop to handle more events. 991133624Snjl */ 992133624Snjl if (i == devcount) 993133624Snjl msleep(&acpi_tz_proc, &thermal_mutex, PZERO | PDROP, "tzpoll", 994133624Snjl hz * acpi_tz_polling_rate); 995133624Snjl else 996133624Snjl ACPI_UNLOCK(thermal); 99791126Smsmith } 99891126Smsmith} 999148138Sume 1000148138Sumestatic int 1001148138Sumeacpi_tz_cpufreq_restore(struct acpi_tz_softc *sc) 1002148138Sume{ 1003148138Sume device_t dev; 1004148138Sume int error; 1005148138Sume 1006148138Sume if (!sc->tz_cooling_updated) 1007148138Sume return (0); 1008148138Sume if ((dev = devclass_get_device(devclass_find("cpufreq"), 0)) == NULL) 1009148138Sume return (ENXIO); 1010148138Sume ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 1011149201Sume "temperature %d.%dC: resuming previous clock speed (%d MHz)\n", 1012149201Sume TZ_KELVTOC(sc->tz_temperature), sc->tz_cooling_saved_freq); 1013148138Sume error = CPUFREQ_SET(dev, NULL, CPUFREQ_PRIO_KERN); 1014148138Sume if (error == 0) 1015148138Sume sc->tz_cooling_updated = FALSE; 1016148138Sume return (error); 1017148138Sume} 1018148138Sume 1019148138Sumestatic int 1020148138Sumeacpi_tz_cpufreq_update(struct acpi_tz_softc *sc, int req) 1021148138Sume{ 1022148138Sume device_t dev; 1023148138Sume struct cf_level *levels; 1024148138Sume int num_levels, error, freq, desired_freq, perf, i; 1025148138Sume 1026148138Sume levels = malloc(CPUFREQ_MAX_LEVELS * sizeof(*levels), M_TEMP, M_NOWAIT); 1027148138Sume if (levels == NULL) 1028148138Sume return (ENOMEM); 1029148138Sume 1030148138Sume /* 1031148138Sume * Find the main device, cpufreq0. We don't yet support independent 1032148138Sume * CPU frequency control on SMP. 1033148138Sume */ 1034148138Sume if ((dev = devclass_get_device(devclass_find("cpufreq"), 0)) == NULL) { 1035148138Sume error = ENXIO; 1036148138Sume goto out; 1037148138Sume } 1038148138Sume 1039148138Sume /* Get the current frequency. */ 1040148138Sume error = CPUFREQ_GET(dev, &levels[0]); 1041148138Sume if (error) 1042148138Sume goto out; 1043148138Sume freq = levels[0].total_set.freq; 1044148138Sume 1045148138Sume /* Get the current available frequency levels. */ 1046148138Sume num_levels = CPUFREQ_MAX_LEVELS; 1047148138Sume error = CPUFREQ_LEVELS(dev, levels, &num_levels); 1048148138Sume if (error) { 1049148138Sume if (error == E2BIG) 1050148138Sume printf("cpufreq: need to increase CPUFREQ_MAX_LEVELS\n"); 1051148138Sume goto out; 1052148138Sume } 1053148138Sume 1054148138Sume /* Calculate the desired frequency as a percent of the max frequency. */ 1055148138Sume perf = 100 * freq / levels[0].total_set.freq - req; 1056148138Sume if (perf < 0) 1057148138Sume perf = 0; 1058148138Sume else if (perf > 100) 1059148138Sume perf = 100; 1060148138Sume desired_freq = levels[0].total_set.freq * perf / 100; 1061148138Sume 1062149201Sume if (desired_freq < freq) { 1063148138Sume /* Find the closest available frequency, rounding down. */ 1064148138Sume for (i = 0; i < num_levels; i++) 1065148138Sume if (levels[i].total_set.freq <= desired_freq) 1066148138Sume break; 1067148138Sume 1068148138Sume /* If we didn't find a relevant setting, use the lowest. */ 1069148138Sume if (i == num_levels) 1070148138Sume i--; 1071148138Sume } else { 1072149201Sume /* If we didn't decrease frequency yet, don't increase it. */ 1073149201Sume if (!sc->tz_cooling_updated) { 1074149201Sume sc->tz_cooling_active = FALSE; 1075149201Sume goto out; 1076149201Sume } 1077149201Sume 1078149201Sume /* Use saved cpu frequency as maximum value. */ 1079149201Sume if (desired_freq > sc->tz_cooling_saved_freq) 1080149201Sume desired_freq = sc->tz_cooling_saved_freq; 1081149201Sume 1082148138Sume /* Find the closest available frequency, rounding up. */ 1083148138Sume for (i = num_levels - 1; i >= 0; i--) 1084148138Sume if (levels[i].total_set.freq >= desired_freq) 1085148138Sume break; 1086148138Sume 1087148138Sume /* If we didn't find a relevant setting, use the highest. */ 1088148138Sume if (i == -1) 1089148138Sume i++; 1090148138Sume 1091149201Sume /* If we're going to the highest frequency, restore the old setting. */ 1092149201Sume if (i == 0 || desired_freq == sc->tz_cooling_saved_freq) { 1093149201Sume error = acpi_tz_cpufreq_restore(sc); 1094149201Sume if (error == 0) 1095149201Sume sc->tz_cooling_active = FALSE; 1096149201Sume goto out; 1097149201Sume } 1098148138Sume } 1099148138Sume 1100148138Sume /* If we are going to a new frequency, activate it. */ 1101148138Sume if (levels[i].total_set.freq != freq) { 1102148138Sume ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 1103148138Sume "temperature %d.%dC: %screasing clock speed " 1104148138Sume "from %d MHz to %d MHz\n", 1105148138Sume TZ_KELVTOC(sc->tz_temperature), 1106148138Sume (freq > levels[i].total_set.freq) ? "de" : "in", 1107148138Sume freq, levels[i].total_set.freq); 1108148138Sume error = CPUFREQ_SET(dev, &levels[i], CPUFREQ_PRIO_KERN); 1109149201Sume if (error == 0 && !sc->tz_cooling_updated) { 1110149201Sume sc->tz_cooling_saved_freq = freq; 1111148138Sume sc->tz_cooling_updated = TRUE; 1112149201Sume } 1113148138Sume } 1114148138Sume 1115148138Sumeout: 1116148138Sume if (levels) 1117148138Sume free(levels, M_TEMP); 1118148138Sume return (error); 1119148138Sume} 1120148138Sume 1121148138Sume/* 1122148138Sume * Passive cooling thread; monitors current temperature according to the 1123148138Sume * cooling interval and calculates whether to scale back CPU frequency. 1124148138Sume */ 1125148138Sumestatic void 1126148138Sumeacpi_tz_cooling_thread(void *arg) 1127148138Sume{ 1128148138Sume struct acpi_tz_softc *sc; 1129149450Sume int error, perf, curr_temp, prev_temp; 1130148138Sume 1131148138Sume ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 1132148138Sume 1133148138Sume sc = (struct acpi_tz_softc *)arg; 1134148138Sume 1135149450Sume prev_temp = sc->tz_temperature; 1136148138Sume while (sc->tz_cooling_enabled) { 1137149450Sume if (sc->tz_cooling_active) 1138149450Sume (void)acpi_tz_get_temperature(sc); 1139149450Sume curr_temp = sc->tz_temperature; 1140149450Sume if (curr_temp >= sc->tz_zone.psv) 1141148138Sume sc->tz_cooling_active = TRUE; 1142148138Sume if (sc->tz_cooling_active) { 1143149450Sume perf = sc->tz_zone.tc1 * (curr_temp - prev_temp) + 1144149450Sume sc->tz_zone.tc2 * (curr_temp - sc->tz_zone.psv); 1145148138Sume perf /= 10; 1146148138Sume 1147148138Sume if (perf != 0) { 1148148138Sume error = acpi_tz_cpufreq_update(sc, perf); 1149148138Sume 1150148138Sume /* 1151148138Sume * If error and not simply a higher priority setting was 1152148138Sume * active, disable cooling. 1153148138Sume */ 1154148138Sume if (error != 0 && error != EPERM) { 1155148138Sume device_printf(sc->tz_dev, 1156148138Sume "failed to set new freq, disabling passive cooling\n"); 1157148138Sume sc->tz_cooling_enabled = FALSE; 1158148138Sume } 1159148138Sume } 1160148138Sume } 1161149450Sume prev_temp = curr_temp; 1162148138Sume tsleep(&sc->tz_cooling_proc, PZERO, "cooling", 1163148138Sume hz * sc->tz_zone.tsp / 10); 1164148138Sume } 1165148138Sume if (sc->tz_cooling_active) { 1166148138Sume acpi_tz_cpufreq_restore(sc); 1167148138Sume sc->tz_cooling_active = FALSE; 1168148138Sume } 1169148703Sume sc->tz_cooling_proc = NULL; 1170148138Sume ACPI_LOCK(thermal); 1171148703Sume sc->tz_cooling_proc_running = FALSE; 1172148138Sume ACPI_UNLOCK(thermal); 1173172836Sjulian kproc_exit(0); 1174148138Sume} 1175148138Sume 1176148138Sume/* 1177148138Sume * TODO: We ignore _PSL (list of cooling devices) since cpufreq enumerates 1178148138Sume * all CPUs for us. However, it's possible in the future _PSL will 1179148138Sume * reference non-CPU devices so we may want to support it then. 1180148138Sume */ 1181148138Sumestatic int 1182148138Sumeacpi_tz_cooling_is_available(struct acpi_tz_softc *sc) 1183148138Sume{ 1184148138Sume return (sc->tz_zone.tc1 != -1 && sc->tz_zone.tc2 != -1 && 1185148138Sume sc->tz_zone.tsp != -1 && sc->tz_zone.tsp != 0 && 1186148138Sume sc->tz_zone.psv != -1); 1187148138Sume} 1188148138Sume 1189148138Sumestatic int 1190148138Sumeacpi_tz_cooling_thread_start(struct acpi_tz_softc *sc) 1191148138Sume{ 1192148138Sume int error; 1193148138Sume 1194148703Sume ACPI_LOCK(thermal); 1195148703Sume if (sc->tz_cooling_proc_running) { 1196148703Sume ACPI_UNLOCK(thermal); 1197148703Sume return (0); 1198148703Sume } 1199148703Sume sc->tz_cooling_proc_running = TRUE; 1200148703Sume ACPI_UNLOCK(thermal); 1201148138Sume error = 0; 1202148138Sume if (sc->tz_cooling_proc == NULL) { 1203209062Savg error = kproc_create(acpi_tz_cooling_thread, sc, 1204209062Savg &sc->tz_cooling_proc, RFHIGHPID, 0, "acpi_cooling%d", 1205148138Sume device_get_unit(sc->tz_dev)); 1206148703Sume if (error != 0) { 1207148138Sume device_printf(sc->tz_dev, "could not create thread - %d", error); 1208148703Sume ACPI_LOCK(thermal); 1209148703Sume sc->tz_cooling_proc_running = FALSE; 1210148703Sume ACPI_UNLOCK(thermal); 1211148703Sume } 1212148138Sume } 1213148138Sume return (error); 1214148138Sume} 1215