acpi_thermal.c revision 174889
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 174889 2007-12-24 16:32:14Z ume $"); 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 48150003Sobrien#include <contrib/dev/acpica/acpi.h> 4967761Smsmith#include <dev/acpica/acpivar.h> 5067761Smsmith 51119529Snjl/* Hooks for the ACPI CA debugging infrastructure */ 5278999Smsmith#define _COMPONENT ACPI_THERMAL 5391126SmsmithACPI_MODULE_NAME("THERMAL") 5469744Smsmith 5571874Smsmith#define TZ_ZEROC 2732 56160657Snjl#define TZ_KELVTOC(x) (((x) - TZ_ZEROC) / 10), abs(((x) - TZ_ZEROC) % 10) 5767761Smsmith 58125366Snjl#define TZ_NOTIFY_TEMPERATURE 0x80 /* Temperature changed. */ 59125366Snjl#define TZ_NOTIFY_LEVELS 0x81 /* Cooling levels changed. */ 60125366Snjl#define TZ_NOTIFY_DEVICES 0x82 /* Device lists changed. */ 61125366Snjl#define TZ_NOTIFY_CRITICAL 0xcc /* Fake notify that _CRT/_HOT reached. */ 6278915Smsmith 63125335Snjl/* Check for temperature changes every 10 seconds by default */ 64125335Snjl#define TZ_POLLRATE 10 6578915Smsmith 66125335Snjl/* Make sure the reported temperature is valid for this number of polls. */ 67125335Snjl#define TZ_VALIDCHECKS 3 68125335Snjl 69125366Snjl/* Notify the user we will be shutting down in one more poll cycle. */ 70125366Snjl#define TZ_NOTIFYCOUNT (TZ_VALIDCHECKS - 1) 71125366Snjl 72119529Snjl/* ACPI spec defines this */ 73119529Snjl#define TZ_NUMLEVELS 10 7479375Smsmithstruct acpi_tz_zone { 7578915Smsmith int ac[TZ_NUMLEVELS]; 7678915Smsmith ACPI_BUFFER al[TZ_NUMLEVELS]; 7778915Smsmith int crt; 7878915Smsmith int hot; 7978915Smsmith ACPI_BUFFER psl; 8078915Smsmith int psv; 8178915Smsmith int tc1; 8278915Smsmith int tc2; 8378915Smsmith int tsp; 8478915Smsmith int tzp; 8578915Smsmith}; 8678915Smsmith 8767761Smsmithstruct acpi_tz_softc { 88119529Snjl device_t tz_dev; 89119529Snjl ACPI_HANDLE tz_handle; /*Thermal zone handle*/ 90119529Snjl int tz_temperature; /*Current temperature*/ 91119529Snjl int tz_active; /*Current active cooling*/ 9279375Smsmith#define TZ_ACTIVE_NONE -1 93119529Snjl int tz_requested; /*Minimum active cooling*/ 94119529Snjl int tz_thflags; /*Current temp-related flags*/ 9579375Smsmith#define TZ_THFLAG_NONE 0 9679375Smsmith#define TZ_THFLAG_PSV (1<<0) 9779375Smsmith#define TZ_THFLAG_HOT (1<<2) 98148138Sume#define TZ_THFLAG_CRT (1<<3) 9979283Smsmith int tz_flags; 100119529Snjl#define TZ_FLAG_NO_SCP (1<<0) /*No _SCP method*/ 101119529Snjl#define TZ_FLAG_GETPROFILE (1<<1) /*Get power_profile in timeout*/ 102133624Snjl#define TZ_FLAG_GETSETTINGS (1<<2) /*Get devs/setpoints*/ 103119529Snjl struct timespec tz_cooling_started; 104119529Snjl /*Current cooling starting time*/ 10579283Smsmith 106119529Snjl struct sysctl_ctx_list tz_sysctl_ctx; 10779283Smsmith struct sysctl_oid *tz_sysctl_tree; 108133624Snjl eventhandler_tag tz_event; 109133624Snjl 110119529Snjl struct acpi_tz_zone tz_zone; /*Thermal zone parameters*/ 111125335Snjl int tz_validchecks; 112148138Sume 113148138Sume /* passive cooling */ 114148138Sume struct proc *tz_cooling_proc; 115148703Sume int tz_cooling_proc_running; 116148138Sume int tz_cooling_enabled; 117148138Sume int tz_cooling_active; 118148138Sume int tz_cooling_updated; 119149201Sume int tz_cooling_saved_freq; 12067761Smsmith}; 12167761Smsmith 122148138Sume#define CPUFREQ_MAX_LEVELS 64 /* XXX cpufreq should export this */ 123148138Sume 12467761Smsmithstatic int acpi_tz_probe(device_t dev); 12567761Smsmithstatic int acpi_tz_attach(device_t dev); 12678915Smsmithstatic int acpi_tz_establish(struct acpi_tz_softc *sc); 127119529Snjlstatic void acpi_tz_monitor(void *Context); 12878915Smsmithstatic void acpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg); 12978915Smsmithstatic void acpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg); 130119529Snjlstatic void acpi_tz_getparam(struct acpi_tz_softc *sc, char *node, 131119529Snjl int *data); 13279283Smsmithstatic void acpi_tz_sanity(struct acpi_tz_softc *sc, int *val, char *what); 13379375Smsmithstatic int acpi_tz_active_sysctl(SYSCTL_HANDLER_ARGS); 134148138Sumestatic int acpi_tz_cooling_sysctl(SYSCTL_HANDLER_ARGS); 135160657Snjlstatic int acpi_tz_temp_sysctl(SYSCTL_HANDLER_ARGS); 136174889Sumestatic int acpi_tz_passive_sysctl(SYSCTL_HANDLER_ARGS); 137119529Snjlstatic void acpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, 138119529Snjl void *context); 139133624Snjlstatic void acpi_tz_signal(struct acpi_tz_softc *sc, int flags); 140133624Snjlstatic void acpi_tz_timeout(struct acpi_tz_softc *sc, int flags); 14191640Siwasakistatic void acpi_tz_power_profile(void *arg); 14291126Smsmithstatic void acpi_tz_thread(void *arg); 143148138Sumestatic int acpi_tz_cooling_is_available(struct acpi_tz_softc *sc); 144148138Sumestatic int acpi_tz_cooling_thread_start(struct acpi_tz_softc *sc); 14591126Smsmith 14667761Smsmithstatic device_method_t acpi_tz_methods[] = { 14767761Smsmith /* Device interface */ 14867761Smsmith DEVMETHOD(device_probe, acpi_tz_probe), 14967761Smsmith DEVMETHOD(device_attach, acpi_tz_attach), 15067761Smsmith 15167761Smsmith {0, 0} 15267761Smsmith}; 15367761Smsmith 15467761Smsmithstatic driver_t acpi_tz_driver = { 15567761Smsmith "acpi_tz", 15667761Smsmith acpi_tz_methods, 15767761Smsmith sizeof(struct acpi_tz_softc), 15867761Smsmith}; 15967761Smsmith 16089054Smsmithstatic devclass_t acpi_tz_devclass; 16167761SmsmithDRIVER_MODULE(acpi_tz, acpi, acpi_tz_driver, acpi_tz_devclass, 0, 0); 162128071SnjlMODULE_DEPEND(acpi_tz, acpi, 1, 1, 1); 16367761Smsmith 16479283Smsmithstatic struct sysctl_ctx_list acpi_tz_sysctl_ctx; 16579283Smsmithstatic struct sysctl_oid *acpi_tz_sysctl_tree; 16679283Smsmith 167119529Snjl/* Minimum cooling run time */ 168160657Snjlstatic int acpi_tz_min_runtime; 16988420Siwasakistatic int acpi_tz_polling_rate = TZ_POLLRATE; 170160657Snjlstatic int acpi_tz_override; 17185699Siwasaki 172119529Snjl/* Timezone polling thread */ 173119529Snjlstatic struct proc *acpi_tz_proc; 174133624SnjlACPI_LOCK_DECL(thermal, "ACPI thermal zone"); 175119529Snjl 17667761Smsmithstatic int 17767761Smsmithacpi_tz_probe(device_t dev) 17867761Smsmith{ 17978999Smsmith int result; 180148138Sume 181119529Snjl if (acpi_get_type(dev) == ACPI_TYPE_THERMAL && !acpi_disabled("thermal")) { 182120453Snjl device_set_desc(dev, "Thermal Zone"); 18378999Smsmith result = -10; 184133624Snjl } else 18578999Smsmith result = ENXIO; 186119529Snjl return (result); 18767761Smsmith} 18867761Smsmith 18967761Smsmithstatic int 19067761Smsmithacpi_tz_attach(device_t dev) 19167761Smsmith{ 19267761Smsmith struct acpi_tz_softc *sc; 19379283Smsmith struct acpi_softc *acpi_sc; 19478915Smsmith int error; 19579283Smsmith char oidname[8]; 19667761Smsmith 19796926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 19869744Smsmith 19967761Smsmith sc = device_get_softc(dev); 20067761Smsmith sc->tz_dev = dev; 20167761Smsmith sc->tz_handle = acpi_get_handle(dev); 20279375Smsmith sc->tz_requested = TZ_ACTIVE_NONE; 203135548Snjl sc->tz_active = TZ_ACTIVE_NONE; 204135548Snjl sc->tz_thflags = TZ_THFLAG_NONE; 205148138Sume sc->tz_cooling_proc = NULL; 206148703Sume sc->tz_cooling_proc_running = FALSE; 207148138Sume sc->tz_cooling_active = FALSE; 208148138Sume sc->tz_cooling_updated = FALSE; 20967761Smsmith 21078915Smsmith /* 211148138Sume * Always attempt to enable passive cooling for tz0. Users can enable 212148138Sume * it for other zones manually for now. 213148138Sume * 214148138Sume * XXX We need to test if multiple zones conflict with each other 215148138Sume * since cpufreq currently sets all CPUs to the given frequency whereas 216148138Sume * it's possible for different thermal zones to specify independent 217148138Sume * settings for multiple CPUs. 218148138Sume */ 219148138Sume sc->tz_cooling_enabled = (device_get_unit(dev) == 0); 220148138Sume 221148138Sume /* 22278915Smsmith * Parse the current state of the thermal zone and build control 223133624Snjl * structures. We don't need to worry about interference with the 224133624Snjl * control thread since we haven't fully attached this device yet. 22578915Smsmith */ 22678915Smsmith if ((error = acpi_tz_establish(sc)) != 0) 227133624Snjl return (error); 228133624Snjl 22978915Smsmith /* 23078915Smsmith * Register for any Notify events sent to this zone. 23178915Smsmith */ 232148138Sume AcpiInstallNotifyHandler(sc->tz_handle, ACPI_DEVICE_NOTIFY, 23378999Smsmith acpi_tz_notify_handler, sc); 23470271Stakawata 23571874Smsmith /* 23679283Smsmith * Create our sysctl nodes. 23779283Smsmith * 23879283Smsmith * XXX we need a mechanism for adding nodes under ACPI. 23979283Smsmith */ 24079283Smsmith if (device_get_unit(dev) == 0) { 24179283Smsmith acpi_sc = acpi_device_get_parent_softc(dev); 24279283Smsmith sysctl_ctx_init(&acpi_tz_sysctl_ctx); 24379283Smsmith acpi_tz_sysctl_tree = SYSCTL_ADD_NODE(&acpi_tz_sysctl_ctx, 244119529Snjl SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), 245119529Snjl OID_AUTO, "thermal", CTLFLAG_RD, 0, ""); 24685699Siwasaki SYSCTL_ADD_INT(&acpi_tz_sysctl_ctx, 24785699Siwasaki SYSCTL_CHILDREN(acpi_tz_sysctl_tree), 248159476Snjl OID_AUTO, "min_runtime", CTLFLAG_RW, 249119529Snjl &acpi_tz_min_runtime, 0, 250119529Snjl "minimum cooling run time in sec"); 25188420Siwasaki SYSCTL_ADD_INT(&acpi_tz_sysctl_ctx, 25288420Siwasaki SYSCTL_CHILDREN(acpi_tz_sysctl_tree), 253159476Snjl OID_AUTO, "polling_rate", CTLFLAG_RW, 25488420Siwasaki &acpi_tz_polling_rate, 0, "monitor polling rate"); 255160657Snjl SYSCTL_ADD_INT(&acpi_tz_sysctl_ctx, 256160657Snjl SYSCTL_CHILDREN(acpi_tz_sysctl_tree), OID_AUTO, 257160657Snjl "user_override", CTLFLAG_RW, &acpi_tz_override, 0, 258160657Snjl "allow override of thermal settings"); 25979283Smsmith } 26079283Smsmith sysctl_ctx_init(&sc->tz_sysctl_ctx); 26179283Smsmith sprintf(oidname, "tz%d", device_get_unit(dev)); 26279283Smsmith sc->tz_sysctl_tree = SYSCTL_ADD_NODE(&sc->tz_sysctl_ctx, 263119529Snjl SYSCTL_CHILDREN(acpi_tz_sysctl_tree), 264119529Snjl OID_AUTO, oidname, CTLFLAG_RD, 0, ""); 265134541Speter SYSCTL_ADD_OPAQUE(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 266134541Speter OID_AUTO, "temperature", CTLFLAG_RD, &sc->tz_temperature, 267134961Snjl sizeof(sc->tz_temperature), "IK", 268134961Snjl "current thermal zone temperature"); 26979375Smsmith SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 27079375Smsmith OID_AUTO, "active", CTLTYPE_INT | CTLFLAG_RW, 271160657Snjl sc, 0, acpi_tz_active_sysctl, "I", "cooling is active"); 272148138Sume SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 273148138Sume OID_AUTO, "passive_cooling", CTLTYPE_INT | CTLFLAG_RW, 274160657Snjl sc, 0, acpi_tz_cooling_sysctl, "I", 275160657Snjl "enable passive (speed reduction) cooling"); 276148138Sume 27779283Smsmith SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 27879375Smsmith OID_AUTO, "thermal_flags", CTLFLAG_RD, 27979375Smsmith &sc->tz_thflags, 0, "thermal zone flags"); 280160657Snjl SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 281160657Snjl OID_AUTO, "_PSV", CTLTYPE_INT | CTLFLAG_RW, 282160657Snjl sc, offsetof(struct acpi_tz_softc, tz_zone.psv), 283160657Snjl acpi_tz_temp_sysctl, "IK", "passive cooling temp setpoint"); 284160657Snjl SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 285160657Snjl OID_AUTO, "_HOT", CTLTYPE_INT | CTLFLAG_RW, 286160657Snjl sc, offsetof(struct acpi_tz_softc, tz_zone.hot), 287160657Snjl acpi_tz_temp_sysctl, "IK", 288160657Snjl "too hot temp setpoint (suspend now)"); 289160657Snjl SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 290160657Snjl OID_AUTO, "_CRT", CTLTYPE_INT | CTLFLAG_RW, 291160657Snjl sc, offsetof(struct acpi_tz_softc, tz_zone.crt), 292160657Snjl acpi_tz_temp_sysctl, "IK", 293160657Snjl "critical temp setpoint (shutdown now)"); 29486399Siwasaki SYSCTL_ADD_OPAQUE(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), 29586399Siwasaki OID_AUTO, "_ACx", CTLFLAG_RD, &sc->tz_zone.ac, 296134541Speter sizeof(sc->tz_zone.ac), "IK", ""); 297174889Sume 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 328148138Sume /* Create a thread to handle passive cooling for each zone if enabled. */ 329148138Sume if (sc->tz_cooling_enabled) { 330148138Sume if (acpi_tz_cooling_is_available(sc)) { 331148138Sume error = acpi_tz_cooling_thread_start(sc); 332148138Sume if (error != 0) { 333148138Sume sc->tz_cooling_enabled = FALSE; 334148138Sume goto out; 335148138Sume } 336148138Sume } else 337148138Sume sc->tz_cooling_enabled = FALSE; 338148138Sume } 339148138Sume 34079375Smsmith /* 341133624Snjl * Flag the event handler for a manual invocation by our timeout. 342133624Snjl * We defer it like this so that the rest of the subsystem has time 343133624Snjl * to come up. Don't bother evaluating/printing the temperature at 344133624Snjl * this point; on many systems it'll be bogus until the EC is running. 34571874Smsmith */ 346133624Snjl sc->tz_flags |= TZ_FLAG_GETPROFILE; 34778999Smsmith 348133624Snjlout: 349133624Snjl if (error != 0) { 350133624Snjl EVENTHANDLER_DEREGISTER(power_profile_change, sc->tz_event); 351133624Snjl AcpiRemoveNotifyHandler(sc->tz_handle, ACPI_DEVICE_NOTIFY, 352133624Snjl acpi_tz_notify_handler); 353133624Snjl sysctl_ctx_free(&sc->tz_sysctl_ctx); 35491126Smsmith } 355119529Snjl return_VALUE (error); 35667761Smsmith} 35770271Stakawata 35878915Smsmith/* 35978915Smsmith * Parse the current state of this thermal zone and set up to use it. 36078915Smsmith * 36178915Smsmith * Note that we may have previous state, which will have to be discarded. 36278915Smsmith */ 36378915Smsmithstatic int 36478915Smsmithacpi_tz_establish(struct acpi_tz_softc *sc) 36578915Smsmith{ 36678915Smsmith ACPI_OBJECT *obj; 36778915Smsmith int i; 36878915Smsmith char nbuf[8]; 369148138Sume 37096926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 37178915Smsmith 372134909Snjl /* Erase any existing state. */ 37378915Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) 37479375Smsmith if (sc->tz_zone.al[i].Pointer != NULL) 37579375Smsmith AcpiOsFree(sc->tz_zone.al[i].Pointer); 37679375Smsmith if (sc->tz_zone.psl.Pointer != NULL) 37779375Smsmith AcpiOsFree(sc->tz_zone.psl.Pointer); 37878915Smsmith 379149449Sume /* 380149449Sume * XXX: We initialize only ACPI_BUFFER to avoid race condition 381149449Sume * with passive cooling thread which refers psv, tc1, tc2 and tsp. 382149449Sume */ 383149449Sume bzero(sc->tz_zone.ac, sizeof(sc->tz_zone.ac)); 384149449Sume bzero(sc->tz_zone.al, sizeof(sc->tz_zone.al)); 385149449Sume bzero(&sc->tz_zone.psl, sizeof(sc->tz_zone.psl)); 386149449Sume 387119529Snjl /* Evaluate thermal zone parameters. */ 38878915Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) { 38978915Smsmith sprintf(nbuf, "_AC%d", i); 39079375Smsmith acpi_tz_getparam(sc, nbuf, &sc->tz_zone.ac[i]); 39178915Smsmith sprintf(nbuf, "_AL%d", i); 39291126Smsmith sc->tz_zone.al[i].Length = ACPI_ALLOCATE_BUFFER; 39391126Smsmith sc->tz_zone.al[i].Pointer = NULL; 39491126Smsmith AcpiEvaluateObject(sc->tz_handle, nbuf, NULL, &sc->tz_zone.al[i]); 39579375Smsmith obj = (ACPI_OBJECT *)sc->tz_zone.al[i].Pointer; 39678915Smsmith if (obj != NULL) { 397119529Snjl /* Should be a package containing a list of power objects */ 39878915Smsmith if (obj->Type != ACPI_TYPE_PACKAGE) { 399119529Snjl device_printf(sc->tz_dev, "%s has unknown type %d, rejecting\n", 40078915Smsmith nbuf, obj->Type); 401119529Snjl return_VALUE (ENXIO); 40278915Smsmith } 40378915Smsmith } 40478915Smsmith } 40579375Smsmith acpi_tz_getparam(sc, "_CRT", &sc->tz_zone.crt); 40679375Smsmith acpi_tz_getparam(sc, "_HOT", &sc->tz_zone.hot); 40791126Smsmith sc->tz_zone.psl.Length = ACPI_ALLOCATE_BUFFER; 40891126Smsmith sc->tz_zone.psl.Pointer = NULL; 40991126Smsmith AcpiEvaluateObject(sc->tz_handle, "_PSL", NULL, &sc->tz_zone.psl); 41079375Smsmith acpi_tz_getparam(sc, "_PSV", &sc->tz_zone.psv); 41179375Smsmith acpi_tz_getparam(sc, "_TC1", &sc->tz_zone.tc1); 41279375Smsmith acpi_tz_getparam(sc, "_TC2", &sc->tz_zone.tc2); 41379375Smsmith acpi_tz_getparam(sc, "_TSP", &sc->tz_zone.tsp); 41479375Smsmith acpi_tz_getparam(sc, "_TZP", &sc->tz_zone.tzp); 41578915Smsmith 41678915Smsmith /* 41779283Smsmith * Sanity-check the values we've been given. 41879283Smsmith * 41979283Smsmith * XXX what do we do about systems that give us the same value for 42079283Smsmith * more than one of these setpoints? 42179283Smsmith */ 42279375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.crt, "_CRT"); 42379375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.hot, "_HOT"); 42479375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.psv, "_PSV"); 42579283Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) 42679375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.ac[i], "_ACx"); 42779283Smsmith 428119529Snjl return_VALUE (0); 42978915Smsmith} 43078915Smsmith 431133624Snjlstatic char *aclevel_string[] = { 432133624Snjl "NONE", "_AC0", "_AC1", "_AC2", "_AC3", "_AC4", 433133624Snjl "_AC5", "_AC6", "_AC7", "_AC8", "_AC9" 434133624Snjl}; 43585699Siwasaki 43685699Siwasakistatic __inline const char * 43785699Siwasakiacpi_tz_aclevel_string(int active) 43885699Siwasaki{ 439133624Snjl if (active < -1 || active >= TZ_NUMLEVELS) 440133624Snjl return (aclevel_string[0]); 44185699Siwasaki 442133624Snjl return (aclevel_string[active + 1]); 44385699Siwasaki} 44485699Siwasaki 44578915Smsmith/* 446149450Sume * Get the current temperature. 447149450Sume */ 448149450Sumestatic int 449149450Sumeacpi_tz_get_temperature(struct acpi_tz_softc *sc) 450149450Sume{ 451149450Sume int temp; 452149450Sume ACPI_STATUS status; 453167249Snjl static char *tmp_name = "_TMP"; 454149450Sume 455149482Skan ACPI_FUNCTION_NAME ("acpi_tz_get_temperature"); 456149482Skan 457167249Snjl /* Evaluate the thermal zone's _TMP method. */ 458167249Snjl status = acpi_GetInteger(sc->tz_handle, tmp_name, &temp); 459149450Sume if (ACPI_FAILURE(status)) { 460149450Sume ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 461149450Sume "error fetching current temperature -- %s\n", 462149450Sume AcpiFormatException(status)); 463149450Sume return (FALSE); 464149450Sume } 465149450Sume 466167249Snjl /* Check it for validity. */ 467167249Snjl acpi_tz_sanity(sc, &temp, tmp_name); 468167249Snjl if (temp == -1) 469167249Snjl return (FALSE); 470167249Snjl 471149450Sume ACPI_DEBUG_PRINT((ACPI_DB_VALUES, "got %d.%dC\n", TZ_KELVTOC(temp))); 472149450Sume sc->tz_temperature = temp; 473149450Sume return (TRUE); 474149450Sume} 475149450Sume 476149450Sume/* 47778915Smsmith * Evaluate the condition of a thermal zone, take appropriate actions. 47878915Smsmith */ 47971874Smsmithstatic void 480119529Snjlacpi_tz_monitor(void *Context) 48171874Smsmith{ 482119529Snjl struct acpi_tz_softc *sc; 483119529Snjl struct timespec curtime; 48479283Smsmith int temp; 48578915Smsmith int i; 48679283Smsmith int newactive, newflags; 48770271Stakawata 48896926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 48970271Stakawata 490119529Snjl sc = (struct acpi_tz_softc *)Context; 49188420Siwasaki 492119529Snjl /* Get the current temperature. */ 493149450Sume if (!acpi_tz_get_temperature(sc)) { 49478915Smsmith /* XXX disable zone? go to max cooling? */ 495133624Snjl return_VOID; 49671874Smsmith } 497149450Sume temp = sc->tz_temperature; 49888420Siwasaki 49978915Smsmith /* 50078915Smsmith * Work out what we ought to be doing right now. 50179283Smsmith * 50279283Smsmith * Note that the _ACx levels sort from hot to cold. 50378915Smsmith */ 50479283Smsmith newactive = TZ_ACTIVE_NONE; 50579375Smsmith for (i = TZ_NUMLEVELS - 1; i >= 0; i--) { 506142195Snjl if (sc->tz_zone.ac[i] != -1 && temp >= sc->tz_zone.ac[i]) { 50779283Smsmith newactive = i; 50882967Siwasaki if (sc->tz_active != newactive) { 509119529Snjl ACPI_VPRINT(sc->tz_dev, 510119529Snjl acpi_device_get_parent_softc(sc->tz_dev), 511119529Snjl "_AC%d: temperature %d.%d >= setpoint %d.%d\n", i, 512119529Snjl TZ_KELVTOC(temp), TZ_KELVTOC(sc->tz_zone.ac[i])); 51382967Siwasaki } 51479375Smsmith } 51579375Smsmith } 51679283Smsmith 51785699Siwasaki /* 51885699Siwasaki * We are going to get _ACx level down (colder side), but give a guaranteed 51985699Siwasaki * minimum cooling run time if requested. 52085699Siwasaki */ 52185699Siwasaki if (acpi_tz_min_runtime > 0 && sc->tz_active != TZ_ACTIVE_NONE && 52285699Siwasaki (newactive == TZ_ACTIVE_NONE || newactive > sc->tz_active)) { 523119529Snjl 52485699Siwasaki getnanotime(&curtime); 52585699Siwasaki timespecsub(&curtime, &sc->tz_cooling_started); 526119529Snjl if (curtime.tv_sec < acpi_tz_min_runtime) 52785699Siwasaki newactive = sc->tz_active; 52885699Siwasaki } 52985699Siwasaki 530119529Snjl /* Handle user override of active mode */ 531126662Snjl if (sc->tz_requested != TZ_ACTIVE_NONE && sc->tz_requested < newactive) 53279375Smsmith newactive = sc->tz_requested; 53378915Smsmith 53479375Smsmith /* update temperature-related flags */ 53579375Smsmith newflags = TZ_THFLAG_NONE; 536124439Snjl if (sc->tz_zone.psv != -1 && temp >= sc->tz_zone.psv) 53779375Smsmith newflags |= TZ_THFLAG_PSV; 538124439Snjl if (sc->tz_zone.hot != -1 && temp >= sc->tz_zone.hot) 53979375Smsmith newflags |= TZ_THFLAG_HOT; 540124439Snjl if (sc->tz_zone.crt != -1 && temp >= sc->tz_zone.crt) 54179375Smsmith newflags |= TZ_THFLAG_CRT; 54279375Smsmith 543119529Snjl /* If the active cooling state has changed, we have to switch things. */ 54479283Smsmith if (newactive != sc->tz_active) { 545119529Snjl /* Turn off the cooling devices that are on, if any are */ 54679283Smsmith if (sc->tz_active != TZ_ACTIVE_NONE) 547119529Snjl acpi_ForeachPackageObject( 548119529Snjl (ACPI_OBJECT *)sc->tz_zone.al[sc->tz_active].Pointer, 549119529Snjl acpi_tz_switch_cooler_off, sc); 55078915Smsmith 551119529Snjl /* Turn on cooling devices that are required, if any are */ 552119529Snjl if (newactive != TZ_ACTIVE_NONE) { 553119529Snjl acpi_ForeachPackageObject( 554119529Snjl (ACPI_OBJECT *)sc->tz_zone.al[newactive].Pointer, 555119529Snjl acpi_tz_switch_cooler_on, sc); 556119529Snjl } 55786552Siwasaki ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 558119529Snjl "switched from %s to %s: %d.%dC\n", 559119529Snjl acpi_tz_aclevel_string(sc->tz_active), 560119529Snjl acpi_tz_aclevel_string(newactive), TZ_KELVTOC(temp)); 56179283Smsmith sc->tz_active = newactive; 562142195Snjl getnanotime(&sc->tz_cooling_started); 56379283Smsmith } 56478915Smsmith 565119529Snjl /* XXX (de)activate any passive cooling that may be required. */ 56678915Smsmith 56778915Smsmith /* 568125335Snjl * If the temperature is at _HOT or _CRT, increment our event count. 569125335Snjl * If it has occurred enough times, shutdown the system. This is 570125335Snjl * needed because some systems will report an invalid high temperature 571125335Snjl * for one poll cycle. It is suspected this is due to the embedded 572125335Snjl * controller timing out. A typical value is 138C for one cycle on 573125335Snjl * a system that is otherwise 65C. 574125366Snjl * 575125366Snjl * If we're almost at that threshold, notify the user through devd(8). 57678915Smsmith */ 577125335Snjl if ((newflags & (TZ_THFLAG_HOT | TZ_THFLAG_CRT)) != 0) { 578125366Snjl sc->tz_validchecks++; 579125366Snjl if (sc->tz_validchecks == TZ_VALIDCHECKS) { 580125335Snjl device_printf(sc->tz_dev, 581125335Snjl "WARNING - current temperature (%d.%dC) exceeds safe limits\n", 582125335Snjl TZ_KELVTOC(sc->tz_temperature)); 583125335Snjl shutdown_nice(RB_POWEROFF); 584125366Snjl } else if (sc->tz_validchecks == TZ_NOTIFYCOUNT) 585125366Snjl acpi_UserNotify("Thermal", sc->tz_handle, TZ_NOTIFY_CRITICAL); 586125335Snjl } else { 587125335Snjl sc->tz_validchecks = 0; 58878915Smsmith } 58979375Smsmith sc->tz_thflags = newflags; 59078915Smsmith 59171874Smsmith return_VOID; 59271874Smsmith} 59370271Stakawata 59478915Smsmith/* 595148138Sume * Given an object, verify that it's a reference to a device of some sort, 59678915Smsmith * and try to switch it off. 59778915Smsmith */ 59878915Smsmithstatic void 59978915Smsmithacpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg) 60078915Smsmith{ 601128047Snjl ACPI_HANDLE cooler; 60278915Smsmith 60396926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 60478915Smsmith 605128047Snjl cooler = acpi_GetReference(NULL, obj); 606128047Snjl if (cooler == NULL) { 607128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get handle\n")); 608128047Snjl return_VOID; 609128047Snjl } 610102470Siwasaki 611128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s off\n", 612128047Snjl acpi_name(cooler))); 613128150Snjl acpi_pwr_switch_consumer(cooler, ACPI_STATE_D3); 614119529Snjl 61579375Smsmith return_VOID; 61678915Smsmith} 61778915Smsmith 61878915Smsmith/* 619148138Sume * Given an object, verify that it's a reference to a device of some sort, 62078915Smsmith * and try to switch it on. 62178915Smsmith * 622128047Snjl * XXX replication of off/on function code is bad. 62378915Smsmith */ 62478915Smsmithstatic void 62578915Smsmithacpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg) 62678915Smsmith{ 62778915Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg; 62878999Smsmith ACPI_HANDLE cooler; 62979375Smsmith ACPI_STATUS status; 630148138Sume 63196926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 63278915Smsmith 633128047Snjl cooler = acpi_GetReference(NULL, obj); 634128047Snjl if (cooler == NULL) { 635128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get handle\n")); 636128047Snjl return_VOID; 637128047Snjl } 638102470Siwasaki 639128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s on\n", 640128047Snjl acpi_name(cooler))); 641128047Snjl status = acpi_pwr_switch_consumer(cooler, ACPI_STATE_D0); 642128047Snjl if (ACPI_FAILURE(status)) { 643128047Snjl ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 644128047Snjl "failed to activate %s - %s\n", acpi_name(cooler), 645128047Snjl AcpiFormatException(status)); 64678915Smsmith } 647119529Snjl 648119529Snjl return_VOID; 64978915Smsmith} 65078915Smsmith 65178915Smsmith/* 65278915Smsmith * Read/debug-print a parameter, default it to -1. 65378915Smsmith */ 65478915Smsmithstatic void 65578915Smsmithacpi_tz_getparam(struct acpi_tz_softc *sc, char *node, int *data) 65678915Smsmith{ 65778915Smsmith 65896926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 65978915Smsmith 660126560Snjl if (ACPI_FAILURE(acpi_GetInteger(sc->tz_handle, node, data))) { 66178915Smsmith *data = -1; 66278915Smsmith } else { 663119529Snjl ACPI_DEBUG_PRINT((ACPI_DB_VALUES, "%s.%s = %d\n", 664119529Snjl acpi_name(sc->tz_handle), node, *data)); 66578915Smsmith } 666119529Snjl 667148138Sume return_VOID; 66878915Smsmith} 66979283Smsmith 67079283Smsmith/* 67179283Smsmith * Sanity-check a temperature value. Assume that setpoints 672167249Snjl * should be between 0C and 200C. 67379283Smsmith */ 67479283Smsmithstatic void 67579283Smsmithacpi_tz_sanity(struct acpi_tz_softc *sc, int *val, char *what) 67679283Smsmith{ 677167249Snjl if (*val != -1 && (*val < TZ_ZEROC || *val > TZ_ZEROC + 2000)) { 67879283Smsmith device_printf(sc->tz_dev, "%s value is absurd, ignored (%d.%dC)\n", 67979283Smsmith what, TZ_KELVTOC(*val)); 68079283Smsmith *val = -1; 68179283Smsmith } 68279283Smsmith} 68379375Smsmith 68479375Smsmith/* 68579375Smsmith * Respond to a sysctl on the active state node. 686148138Sume */ 68779375Smsmithstatic int 68879375Smsmithacpi_tz_active_sysctl(SYSCTL_HANDLER_ARGS) 68979375Smsmith{ 69079375Smsmith struct acpi_tz_softc *sc; 69179375Smsmith int active; 69279375Smsmith int error; 69379375Smsmith 69479375Smsmith sc = (struct acpi_tz_softc *)oidp->oid_arg1; 69579375Smsmith active = sc->tz_active; 69679375Smsmith error = sysctl_handle_int(oidp, &active, 0, req); 69779375Smsmith 698119529Snjl /* Error or no new value */ 699119529Snjl if (error != 0 || req->newptr == NULL) 700133624Snjl return (error); 701133624Snjl if (active < -1 || active >= TZ_NUMLEVELS) 702133624Snjl return (EINVAL); 70379375Smsmith 704119529Snjl /* Set new preferred level and re-switch */ 70579375Smsmith sc->tz_requested = active; 706133624Snjl acpi_tz_signal(sc, 0); 707133624Snjl return (0); 70879375Smsmith} 70979375Smsmith 710148138Sumestatic int 711148138Sumeacpi_tz_cooling_sysctl(SYSCTL_HANDLER_ARGS) 712148138Sume{ 713148138Sume struct acpi_tz_softc *sc; 714148138Sume int enabled, error; 715148138Sume 716148138Sume sc = (struct acpi_tz_softc *)oidp->oid_arg1; 717148138Sume enabled = sc->tz_cooling_enabled; 718148138Sume error = sysctl_handle_int(oidp, &enabled, 0, req); 719148138Sume 720148138Sume /* Error or no new value */ 721148138Sume if (error != 0 || req->newptr == NULL) 722148138Sume return (error); 723148138Sume if (enabled != TRUE && enabled != FALSE) 724148138Sume return (EINVAL); 725148138Sume 726148138Sume if (enabled) { 727148138Sume if (acpi_tz_cooling_is_available(sc)) 728148138Sume error = acpi_tz_cooling_thread_start(sc); 729148138Sume else 730148138Sume error = ENODEV; 731148138Sume if (error) 732148138Sume enabled = FALSE; 733148138Sume } 734148138Sume sc->tz_cooling_enabled = enabled; 735148138Sume return (error); 736148138Sume} 737148138Sume 738160657Snjlstatic int 739160657Snjlacpi_tz_temp_sysctl(SYSCTL_HANDLER_ARGS) 740160657Snjl{ 741160657Snjl struct acpi_tz_softc *sc; 742160657Snjl int temp, *temp_ptr; 743160657Snjl int error; 744160657Snjl 745160657Snjl sc = oidp->oid_arg1; 746160657Snjl temp_ptr = (int *)((uintptr_t)sc + oidp->oid_arg2); 747160657Snjl temp = *temp_ptr; 748160657Snjl error = sysctl_handle_int(oidp, &temp, 0, req); 749160657Snjl 750160657Snjl /* Error or no new value */ 751160657Snjl if (error != 0 || req->newptr == NULL) 752160657Snjl return (error); 753160657Snjl 754160657Snjl /* Only allow changing settings if override is set. */ 755160657Snjl if (!acpi_tz_override) 756160657Snjl return (EPERM); 757160657Snjl 758160657Snjl /* Check user-supplied value for sanity. */ 759160657Snjl acpi_tz_sanity(sc, &temp, "user-supplied temp"); 760160657Snjl if (temp == -1) 761160657Snjl return (EINVAL); 762160657Snjl 763160657Snjl *temp_ptr = temp; 764160657Snjl return (0); 765160657Snjl} 766160657Snjl 767174889Sumestatic int 768174889Sumeacpi_tz_passive_sysctl(SYSCTL_HANDLER_ARGS) 769174889Sume{ 770174889Sume struct acpi_tz_softc *sc; 771174889Sume int val, *val_ptr; 772174889Sume int error; 773174889Sume 774174889Sume sc = oidp->oid_arg1; 775174889Sume val_ptr = (int *)((uintptr_t)sc + oidp->oid_arg2); 776174889Sume val = *val_ptr; 777174889Sume error = sysctl_handle_int(oidp, &val, 0, req); 778174889Sume 779174889Sume /* Error or no new value */ 780174889Sume if (error != 0 || req->newptr == NULL) 781174889Sume return (error); 782174889Sume 783174889Sume /* Only allow changing settings if override is set. */ 784174889Sume if (!acpi_tz_override) 785174889Sume return (EPERM); 786174889Sume 787174889Sume *val_ptr = val; 788174889Sume return (0); 789174889Sume} 790174889Sume 79178915Smsmithstatic void 79271874Smsmithacpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context) 79371874Smsmith{ 79478915Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)context; 79578915Smsmith 79696926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 79770271Stakawata 798133624Snjl switch (notify) { 79978915Smsmith case TZ_NOTIFY_TEMPERATURE: 800119529Snjl /* Temperature change occurred */ 801133624Snjl acpi_tz_signal(sc, 0); 80278915Smsmith break; 80378915Smsmith case TZ_NOTIFY_DEVICES: 80478915Smsmith case TZ_NOTIFY_LEVELS: 805119529Snjl /* Zone devices/setpoints changed */ 806133624Snjl acpi_tz_signal(sc, TZ_FLAG_GETSETTINGS); 80778915Smsmith break; 80878915Smsmith default: 80986552Siwasaki ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 810119529Snjl "unknown Notify event 0x%x\n", notify); 81178915Smsmith break; 81271874Smsmith } 813119529Snjl 814121493Snjl acpi_UserNotify("Thermal", h, notify); 815121493Snjl 81671874Smsmith return_VOID; 81771874Smsmith} 81870271Stakawata 819133624Snjlstatic void 820133624Snjlacpi_tz_signal(struct acpi_tz_softc *sc, int flags) 821133624Snjl{ 822133624Snjl ACPI_LOCK(thermal); 823133624Snjl sc->tz_flags |= flags; 824133624Snjl ACPI_UNLOCK(thermal); 825133624Snjl wakeup(&acpi_tz_proc); 826133624Snjl} 827133624Snjl 82878915Smsmith/* 829134909Snjl * Notifies can be generated asynchronously but have also been seen to be 830134909Snjl * triggered by other thermal methods. One system generates a notify of 831134909Snjl * 0x81 when the fan is turned on or off. Another generates it when _SCP 832134909Snjl * is called. To handle these situations, we check the zone via 833134909Snjl * acpi_tz_monitor() before evaluating changes to setpoints or the cooling 834134909Snjl * policy. 83578915Smsmith */ 83678915Smsmithstatic void 837133624Snjlacpi_tz_timeout(struct acpi_tz_softc *sc, int flags) 83878915Smsmith{ 839134909Snjl 840134909Snjl /* Check the current temperature and take action based on it */ 841134909Snjl acpi_tz_monitor(sc); 842134909Snjl 843133624Snjl /* If requested, get the power profile settings. */ 844133624Snjl if (flags & TZ_FLAG_GETPROFILE) 845133624Snjl acpi_tz_power_profile(sc); 84679375Smsmith 847134909Snjl /* 848134909Snjl * If requested, check for new devices/setpoints. After finding them, 849134909Snjl * check if we need to switch fans based on the new values. 850134909Snjl */ 851134909Snjl if (flags & TZ_FLAG_GETSETTINGS) { 852133624Snjl acpi_tz_establish(sc); 853134909Snjl acpi_tz_monitor(sc); 854134909Snjl } 85578915Smsmith 85678915Smsmith /* XXX passive cooling actions? */ 85778915Smsmith} 85879375Smsmith 85979375Smsmith/* 86079375Smsmith * System power profile may have changed; fetch and notify the 86179375Smsmith * thermal zone accordingly. 86279375Smsmith * 86379375Smsmith * Since this can be called from an arbitrary eventhandler, it needs 86479375Smsmith * to get the ACPI lock itself. 86579375Smsmith */ 86679375Smsmithstatic void 86791640Siwasakiacpi_tz_power_profile(void *arg) 86879375Smsmith{ 86979375Smsmith ACPI_STATUS status; 87079375Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg; 87191640Siwasaki int state; 87279375Smsmith 87391640Siwasaki state = power_profile_get_state(); 874119529Snjl if (state != POWER_PROFILE_PERFORMANCE && state != POWER_PROFILE_ECONOMY) 875119529Snjl return; 87691640Siwasaki 87779375Smsmith /* check that we haven't decided there's no _SCP method */ 878119529Snjl if ((sc->tz_flags & TZ_FLAG_NO_SCP) == 0) { 87979375Smsmith 880119529Snjl /* Call _SCP to set the new profile */ 881148138Sume status = acpi_SetInteger(sc->tz_handle, "_SCP", 882126560Snjl (state == POWER_PROFILE_PERFORMANCE) ? 0 : 1); 883119529Snjl if (ACPI_FAILURE(status)) { 88479385Smsmith if (status != AE_NOT_FOUND) 885119529Snjl ACPI_VPRINT(sc->tz_dev, 886119529Snjl acpi_device_get_parent_softc(sc->tz_dev), 887119529Snjl "can't evaluate %s._SCP - %s\n", 888119529Snjl acpi_name(sc->tz_handle), 889119529Snjl AcpiFormatException(status)); 89079375Smsmith sc->tz_flags |= TZ_FLAG_NO_SCP; 89179375Smsmith } else { 892119529Snjl /* We have to re-evaluate the entire zone now */ 893133624Snjl acpi_tz_signal(sc, TZ_FLAG_GETSETTINGS); 89479375Smsmith } 89579375Smsmith } 89679375Smsmith} 89779375Smsmith 89891126Smsmith/* 89991126Smsmith * Thermal zone monitor thread. 90091126Smsmith */ 90191126Smsmithstatic void 90291126Smsmithacpi_tz_thread(void *arg) 90391126Smsmith{ 90491126Smsmith device_t *devs; 90591126Smsmith int devcount, i; 906133624Snjl int flags; 907133624Snjl struct acpi_tz_softc **sc; 90891126Smsmith 90996926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 91091126Smsmith 91191126Smsmith devs = NULL; 91291126Smsmith devcount = 0; 913133624Snjl sc = NULL; 91491126Smsmith 91591126Smsmith for (;;) { 916133624Snjl /* If the number of devices has changed, re-evaluate. */ 917133624Snjl if (devclass_get_maxunit(acpi_tz_devclass) != devcount) { 918133624Snjl if (devs != NULL) { 919133624Snjl free(devs, M_TEMP); 920133624Snjl free(sc, M_TEMP); 921133624Snjl } 922133624Snjl devclass_get_devices(acpi_tz_devclass, &devs, &devcount); 923133624Snjl sc = malloc(sizeof(struct acpi_tz_softc *) * devcount, M_TEMP, 924133624Snjl M_WAITOK | M_ZERO); 925133624Snjl for (i = 0; i < devcount; i++) 926133624Snjl sc[i] = device_get_softc(devs[i]); 927133624Snjl } 92891126Smsmith 929133624Snjl /* Check for temperature events and act on them. */ 930133624Snjl for (i = 0; i < devcount; i++) { 931133624Snjl ACPI_LOCK(thermal); 932133624Snjl flags = sc[i]->tz_flags; 933133624Snjl sc[i]->tz_flags &= TZ_FLAG_NO_SCP; 934133624Snjl ACPI_UNLOCK(thermal); 935133624Snjl acpi_tz_timeout(sc[i], flags); 936133624Snjl } 93791215Smsmith 938133624Snjl /* If more work to do, don't go to sleep yet. */ 939133624Snjl ACPI_LOCK(thermal); 940133624Snjl for (i = 0; i < devcount; i++) { 941133624Snjl if (sc[i]->tz_flags & ~TZ_FLAG_NO_SCP) 942133624Snjl break; 943133624Snjl } 94491126Smsmith 945133624Snjl /* 946133624Snjl * If we have no more work, sleep for a while, setting PDROP so that 947133624Snjl * the mutex will not be reacquired. Otherwise, drop the mutex and 948133624Snjl * loop to handle more events. 949133624Snjl */ 950133624Snjl if (i == devcount) 951133624Snjl msleep(&acpi_tz_proc, &thermal_mutex, PZERO | PDROP, "tzpoll", 952133624Snjl hz * acpi_tz_polling_rate); 953133624Snjl else 954133624Snjl ACPI_UNLOCK(thermal); 95591126Smsmith } 95691126Smsmith} 957148138Sume 958148138Sumestatic int 959148138Sumeacpi_tz_cpufreq_restore(struct acpi_tz_softc *sc) 960148138Sume{ 961148138Sume device_t dev; 962148138Sume int error; 963148138Sume 964148138Sume if (!sc->tz_cooling_updated) 965148138Sume return (0); 966148138Sume if ((dev = devclass_get_device(devclass_find("cpufreq"), 0)) == NULL) 967148138Sume return (ENXIO); 968148138Sume ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 969149201Sume "temperature %d.%dC: resuming previous clock speed (%d MHz)\n", 970149201Sume TZ_KELVTOC(sc->tz_temperature), sc->tz_cooling_saved_freq); 971148138Sume error = CPUFREQ_SET(dev, NULL, CPUFREQ_PRIO_KERN); 972148138Sume if (error == 0) 973148138Sume sc->tz_cooling_updated = FALSE; 974148138Sume return (error); 975148138Sume} 976148138Sume 977148138Sumestatic int 978148138Sumeacpi_tz_cpufreq_update(struct acpi_tz_softc *sc, int req) 979148138Sume{ 980148138Sume device_t dev; 981148138Sume struct cf_level *levels; 982148138Sume int num_levels, error, freq, desired_freq, perf, i; 983148138Sume 984148138Sume levels = malloc(CPUFREQ_MAX_LEVELS * sizeof(*levels), M_TEMP, M_NOWAIT); 985148138Sume if (levels == NULL) 986148138Sume return (ENOMEM); 987148138Sume 988148138Sume /* 989148138Sume * Find the main device, cpufreq0. We don't yet support independent 990148138Sume * CPU frequency control on SMP. 991148138Sume */ 992148138Sume if ((dev = devclass_get_device(devclass_find("cpufreq"), 0)) == NULL) { 993148138Sume error = ENXIO; 994148138Sume goto out; 995148138Sume } 996148138Sume 997148138Sume /* Get the current frequency. */ 998148138Sume error = CPUFREQ_GET(dev, &levels[0]); 999148138Sume if (error) 1000148138Sume goto out; 1001148138Sume freq = levels[0].total_set.freq; 1002148138Sume 1003148138Sume /* Get the current available frequency levels. */ 1004148138Sume num_levels = CPUFREQ_MAX_LEVELS; 1005148138Sume error = CPUFREQ_LEVELS(dev, levels, &num_levels); 1006148138Sume if (error) { 1007148138Sume if (error == E2BIG) 1008148138Sume printf("cpufreq: need to increase CPUFREQ_MAX_LEVELS\n"); 1009148138Sume goto out; 1010148138Sume } 1011148138Sume 1012148138Sume /* Calculate the desired frequency as a percent of the max frequency. */ 1013148138Sume perf = 100 * freq / levels[0].total_set.freq - req; 1014148138Sume if (perf < 0) 1015148138Sume perf = 0; 1016148138Sume else if (perf > 100) 1017148138Sume perf = 100; 1018148138Sume desired_freq = levels[0].total_set.freq * perf / 100; 1019148138Sume 1020149201Sume if (desired_freq < freq) { 1021148138Sume /* Find the closest available frequency, rounding down. */ 1022148138Sume for (i = 0; i < num_levels; i++) 1023148138Sume if (levels[i].total_set.freq <= desired_freq) 1024148138Sume break; 1025148138Sume 1026148138Sume /* If we didn't find a relevant setting, use the lowest. */ 1027148138Sume if (i == num_levels) 1028148138Sume i--; 1029148138Sume } else { 1030149201Sume /* If we didn't decrease frequency yet, don't increase it. */ 1031149201Sume if (!sc->tz_cooling_updated) { 1032149201Sume sc->tz_cooling_active = FALSE; 1033149201Sume goto out; 1034149201Sume } 1035149201Sume 1036149201Sume /* Use saved cpu frequency as maximum value. */ 1037149201Sume if (desired_freq > sc->tz_cooling_saved_freq) 1038149201Sume desired_freq = sc->tz_cooling_saved_freq; 1039149201Sume 1040148138Sume /* Find the closest available frequency, rounding up. */ 1041148138Sume for (i = num_levels - 1; i >= 0; i--) 1042148138Sume if (levels[i].total_set.freq >= desired_freq) 1043148138Sume break; 1044148138Sume 1045148138Sume /* If we didn't find a relevant setting, use the highest. */ 1046148138Sume if (i == -1) 1047148138Sume i++; 1048148138Sume 1049149201Sume /* If we're going to the highest frequency, restore the old setting. */ 1050149201Sume if (i == 0 || desired_freq == sc->tz_cooling_saved_freq) { 1051149201Sume error = acpi_tz_cpufreq_restore(sc); 1052149201Sume if (error == 0) 1053149201Sume sc->tz_cooling_active = FALSE; 1054149201Sume goto out; 1055149201Sume } 1056148138Sume } 1057148138Sume 1058148138Sume /* If we are going to a new frequency, activate it. */ 1059148138Sume if (levels[i].total_set.freq != freq) { 1060148138Sume ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 1061148138Sume "temperature %d.%dC: %screasing clock speed " 1062148138Sume "from %d MHz to %d MHz\n", 1063148138Sume TZ_KELVTOC(sc->tz_temperature), 1064148138Sume (freq > levels[i].total_set.freq) ? "de" : "in", 1065148138Sume freq, levels[i].total_set.freq); 1066148138Sume error = CPUFREQ_SET(dev, &levels[i], CPUFREQ_PRIO_KERN); 1067149201Sume if (error == 0 && !sc->tz_cooling_updated) { 1068149201Sume sc->tz_cooling_saved_freq = freq; 1069148138Sume sc->tz_cooling_updated = TRUE; 1070149201Sume } 1071148138Sume } 1072148138Sume 1073148138Sumeout: 1074148138Sume if (levels) 1075148138Sume free(levels, M_TEMP); 1076148138Sume return (error); 1077148138Sume} 1078148138Sume 1079148138Sume/* 1080148138Sume * Passive cooling thread; monitors current temperature according to the 1081148138Sume * cooling interval and calculates whether to scale back CPU frequency. 1082148138Sume */ 1083148138Sumestatic void 1084148138Sumeacpi_tz_cooling_thread(void *arg) 1085148138Sume{ 1086148138Sume struct acpi_tz_softc *sc; 1087149450Sume int error, perf, curr_temp, prev_temp; 1088148138Sume 1089148138Sume ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 1090148138Sume 1091148138Sume sc = (struct acpi_tz_softc *)arg; 1092148138Sume 1093149450Sume prev_temp = sc->tz_temperature; 1094148138Sume while (sc->tz_cooling_enabled) { 1095149450Sume if (sc->tz_cooling_active) 1096149450Sume (void)acpi_tz_get_temperature(sc); 1097149450Sume curr_temp = sc->tz_temperature; 1098149450Sume if (curr_temp >= sc->tz_zone.psv) 1099148138Sume sc->tz_cooling_active = TRUE; 1100148138Sume if (sc->tz_cooling_active) { 1101149450Sume perf = sc->tz_zone.tc1 * (curr_temp - prev_temp) + 1102149450Sume sc->tz_zone.tc2 * (curr_temp - sc->tz_zone.psv); 1103148138Sume perf /= 10; 1104148138Sume 1105148138Sume if (perf != 0) { 1106148138Sume error = acpi_tz_cpufreq_update(sc, perf); 1107148138Sume 1108148138Sume /* 1109148138Sume * If error and not simply a higher priority setting was 1110148138Sume * active, disable cooling. 1111148138Sume */ 1112148138Sume if (error != 0 && error != EPERM) { 1113148138Sume device_printf(sc->tz_dev, 1114148138Sume "failed to set new freq, disabling passive cooling\n"); 1115148138Sume sc->tz_cooling_enabled = FALSE; 1116148138Sume } 1117148138Sume } 1118148138Sume } 1119149450Sume prev_temp = curr_temp; 1120148138Sume tsleep(&sc->tz_cooling_proc, PZERO, "cooling", 1121148138Sume hz * sc->tz_zone.tsp / 10); 1122148138Sume } 1123148138Sume if (sc->tz_cooling_active) { 1124148138Sume acpi_tz_cpufreq_restore(sc); 1125148138Sume sc->tz_cooling_active = FALSE; 1126148138Sume } 1127148703Sume sc->tz_cooling_proc = NULL; 1128148138Sume ACPI_LOCK(thermal); 1129148703Sume sc->tz_cooling_proc_running = FALSE; 1130148138Sume ACPI_UNLOCK(thermal); 1131172836Sjulian kproc_exit(0); 1132148138Sume} 1133148138Sume 1134148138Sume/* 1135148138Sume * TODO: We ignore _PSL (list of cooling devices) since cpufreq enumerates 1136148138Sume * all CPUs for us. However, it's possible in the future _PSL will 1137148138Sume * reference non-CPU devices so we may want to support it then. 1138148138Sume */ 1139148138Sumestatic int 1140148138Sumeacpi_tz_cooling_is_available(struct acpi_tz_softc *sc) 1141148138Sume{ 1142148138Sume return (sc->tz_zone.tc1 != -1 && sc->tz_zone.tc2 != -1 && 1143148138Sume sc->tz_zone.tsp != -1 && sc->tz_zone.tsp != 0 && 1144148138Sume sc->tz_zone.psv != -1); 1145148138Sume} 1146148138Sume 1147148138Sumestatic int 1148148138Sumeacpi_tz_cooling_thread_start(struct acpi_tz_softc *sc) 1149148138Sume{ 1150148138Sume int error; 1151148138Sume char name[16]; 1152148138Sume 1153148703Sume ACPI_LOCK(thermal); 1154148703Sume if (sc->tz_cooling_proc_running) { 1155148703Sume ACPI_UNLOCK(thermal); 1156148703Sume return (0); 1157148703Sume } 1158148703Sume sc->tz_cooling_proc_running = TRUE; 1159148703Sume ACPI_UNLOCK(thermal); 1160148138Sume error = 0; 1161148138Sume if (sc->tz_cooling_proc == NULL) { 1162148138Sume snprintf(name, sizeof(name), "acpi_cooling%d", 1163148138Sume device_get_unit(sc->tz_dev)); 1164172836Sjulian error = kproc_create(acpi_tz_cooling_thread, sc, 1165148138Sume &sc->tz_cooling_proc, RFHIGHPID, 0, name); 1166148703Sume if (error != 0) { 1167148138Sume device_printf(sc->tz_dev, "could not create thread - %d", error); 1168148703Sume ACPI_LOCK(thermal); 1169148703Sume sc->tz_cooling_proc_running = FALSE; 1170148703Sume ACPI_UNLOCK(thermal); 1171148703Sume } 1172148138Sume } 1173148138Sume return (error); 1174148138Sume} 1175