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$"); 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 56300421Sloos#define TZ_ZEROC 2731 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 /* 314301518Sjhb * Register our power profile event handler. 31579375Smsmith */ 316133624Snjl sc->tz_event = EVENTHANDLER_REGISTER(power_profile_change, 317133624Snjl acpi_tz_power_profile, sc, 0); 31879375Smsmith 319176329Sume /* 320301518Sjhb * Flag the event handler for a manual invocation by our timeout. 321301518Sjhb * We defer it like this so that the rest of the subsystem has time 322301518Sjhb * to come up. Don't bother evaluating/printing the temperature at 323301518Sjhb * this point; on many systems it'll be bogus until the EC is running. 324301518Sjhb */ 325301518Sjhb sc->tz_flags |= TZ_FLAG_GETPROFILE; 326301518Sjhb 327301518Sjhb return_VALUE (0); 328301518Sjhb} 329301518Sjhb 330301518Sjhbstatic void 331301518Sjhbacpi_tz_startup(void *arg __unused) 332301518Sjhb{ 333301518Sjhb struct acpi_tz_softc *sc; 334301518Sjhb device_t *devs; 335301518Sjhb int devcount, error, i; 336301518Sjhb 337301518Sjhb devclass_get_devices(acpi_tz_devclass, &devs, &devcount); 338301562Scem if (devcount == 0) { 339301562Scem free(devs, M_TEMP); 340301518Sjhb return; 341301562Scem } 342301518Sjhb 343301518Sjhb /* 344301518Sjhb * Create thread to service all of the thermal zones. 345301518Sjhb */ 346301518Sjhb error = kproc_create(acpi_tz_thread, NULL, &acpi_tz_proc, RFHIGHPID, 0, 347301518Sjhb "acpi_thermal"); 348301518Sjhb if (error != 0) 349301518Sjhb printf("acpi_tz: could not create thread - %d", error); 350301518Sjhb 351301518Sjhb /* 352176329Sume * Create a thread to handle passive cooling for 1st zone which 353176329Sume * has _PSV, _TSP, _TC1 and _TC2. Users can enable it for other 354176329Sume * zones manually for now. 355176329Sume * 356176329Sume * XXX We enable only one zone to avoid multiple zones conflict 357176329Sume * with each other since cpufreq currently sets all CPUs to the 358176329Sume * given frequency whereas it's possible for different thermal 359176329Sume * zones to specify independent settings for multiple CPUs. 360176329Sume */ 361301518Sjhb for (i = 0; i < devcount; i++) { 362301518Sjhb sc = device_get_softc(devs[i]); 363301518Sjhb if (acpi_tz_cooling_is_available(sc)) { 364301518Sjhb sc->tz_cooling_enabled = TRUE; 365301518Sjhb error = acpi_tz_cooling_thread_start(sc); 366301518Sjhb if (error != 0) { 367301518Sjhb sc->tz_cooling_enabled = FALSE; 368301518Sjhb break; 369301518Sjhb } 370301518Sjhb acpi_tz_cooling_unit = device_get_unit(devs[i]); 371301518Sjhb break; 372176329Sume } 373148138Sume } 374301518Sjhb free(devs, M_TEMP); 37567761Smsmith} 376301518SjhbSYSINIT(acpi_tz, SI_SUB_KICK_SCHEDULER, SI_ORDER_ANY, acpi_tz_startup, NULL); 37770271Stakawata 37878915Smsmith/* 37978915Smsmith * Parse the current state of this thermal zone and set up to use it. 38078915Smsmith * 38178915Smsmith * Note that we may have previous state, which will have to be discarded. 38278915Smsmith */ 38378915Smsmithstatic int 38478915Smsmithacpi_tz_establish(struct acpi_tz_softc *sc) 38578915Smsmith{ 38678915Smsmith ACPI_OBJECT *obj; 38778915Smsmith int i; 38878915Smsmith char nbuf[8]; 389148138Sume 39096926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 39178915Smsmith 392134909Snjl /* Erase any existing state. */ 39378915Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) 39479375Smsmith if (sc->tz_zone.al[i].Pointer != NULL) 39579375Smsmith AcpiOsFree(sc->tz_zone.al[i].Pointer); 39679375Smsmith if (sc->tz_zone.psl.Pointer != NULL) 39779375Smsmith AcpiOsFree(sc->tz_zone.psl.Pointer); 39878915Smsmith 399149449Sume /* 400149449Sume * XXX: We initialize only ACPI_BUFFER to avoid race condition 401149449Sume * with passive cooling thread which refers psv, tc1, tc2 and tsp. 402149449Sume */ 403149449Sume bzero(sc->tz_zone.ac, sizeof(sc->tz_zone.ac)); 404149449Sume bzero(sc->tz_zone.al, sizeof(sc->tz_zone.al)); 405149449Sume bzero(&sc->tz_zone.psl, sizeof(sc->tz_zone.psl)); 406149449Sume 407119529Snjl /* Evaluate thermal zone parameters. */ 40878915Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) { 40978915Smsmith sprintf(nbuf, "_AC%d", i); 41079375Smsmith acpi_tz_getparam(sc, nbuf, &sc->tz_zone.ac[i]); 41178915Smsmith sprintf(nbuf, "_AL%d", i); 41291126Smsmith sc->tz_zone.al[i].Length = ACPI_ALLOCATE_BUFFER; 41391126Smsmith sc->tz_zone.al[i].Pointer = NULL; 41491126Smsmith AcpiEvaluateObject(sc->tz_handle, nbuf, NULL, &sc->tz_zone.al[i]); 41579375Smsmith obj = (ACPI_OBJECT *)sc->tz_zone.al[i].Pointer; 41678915Smsmith if (obj != NULL) { 417119529Snjl /* Should be a package containing a list of power objects */ 41878915Smsmith if (obj->Type != ACPI_TYPE_PACKAGE) { 419119529Snjl device_printf(sc->tz_dev, "%s has unknown type %d, rejecting\n", 42078915Smsmith nbuf, obj->Type); 421119529Snjl return_VALUE (ENXIO); 42278915Smsmith } 42378915Smsmith } 42478915Smsmith } 42579375Smsmith acpi_tz_getparam(sc, "_CRT", &sc->tz_zone.crt); 42679375Smsmith acpi_tz_getparam(sc, "_HOT", &sc->tz_zone.hot); 42791126Smsmith sc->tz_zone.psl.Length = ACPI_ALLOCATE_BUFFER; 42891126Smsmith sc->tz_zone.psl.Pointer = NULL; 42991126Smsmith AcpiEvaluateObject(sc->tz_handle, "_PSL", NULL, &sc->tz_zone.psl); 43079375Smsmith acpi_tz_getparam(sc, "_PSV", &sc->tz_zone.psv); 43179375Smsmith acpi_tz_getparam(sc, "_TC1", &sc->tz_zone.tc1); 43279375Smsmith acpi_tz_getparam(sc, "_TC2", &sc->tz_zone.tc2); 43379375Smsmith acpi_tz_getparam(sc, "_TSP", &sc->tz_zone.tsp); 43479375Smsmith acpi_tz_getparam(sc, "_TZP", &sc->tz_zone.tzp); 43578915Smsmith 43678915Smsmith /* 43779283Smsmith * Sanity-check the values we've been given. 43879283Smsmith * 43979283Smsmith * XXX what do we do about systems that give us the same value for 44079283Smsmith * more than one of these setpoints? 44179283Smsmith */ 44279375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.crt, "_CRT"); 44379375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.hot, "_HOT"); 44479375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.psv, "_PSV"); 44579283Smsmith for (i = 0; i < TZ_NUMLEVELS; i++) 44679375Smsmith acpi_tz_sanity(sc, &sc->tz_zone.ac[i], "_ACx"); 44779283Smsmith 448119529Snjl return_VALUE (0); 44978915Smsmith} 45078915Smsmith 451133624Snjlstatic char *aclevel_string[] = { 452133624Snjl "NONE", "_AC0", "_AC1", "_AC2", "_AC3", "_AC4", 453133624Snjl "_AC5", "_AC6", "_AC7", "_AC8", "_AC9" 454133624Snjl}; 45585699Siwasaki 45685699Siwasakistatic __inline const char * 45785699Siwasakiacpi_tz_aclevel_string(int active) 45885699Siwasaki{ 459133624Snjl if (active < -1 || active >= TZ_NUMLEVELS) 460133624Snjl return (aclevel_string[0]); 46185699Siwasaki 462133624Snjl return (aclevel_string[active + 1]); 46385699Siwasaki} 46485699Siwasaki 46578915Smsmith/* 466149450Sume * Get the current temperature. 467149450Sume */ 468149450Sumestatic int 469149450Sumeacpi_tz_get_temperature(struct acpi_tz_softc *sc) 470149450Sume{ 471149450Sume int temp; 472149450Sume ACPI_STATUS status; 473149450Sume 474149482Skan ACPI_FUNCTION_NAME ("acpi_tz_get_temperature"); 475149482Skan 476167249Snjl /* Evaluate the thermal zone's _TMP method. */ 477255077Sdumbbell status = acpi_GetInteger(sc->tz_handle, acpi_tz_tmp_name, &temp); 478149450Sume if (ACPI_FAILURE(status)) { 479149450Sume ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 480149450Sume "error fetching current temperature -- %s\n", 481149450Sume AcpiFormatException(status)); 482149450Sume return (FALSE); 483149450Sume } 484149450Sume 485167249Snjl /* Check it for validity. */ 486255077Sdumbbell acpi_tz_sanity(sc, &temp, acpi_tz_tmp_name); 487167249Snjl if (temp == -1) 488167249Snjl return (FALSE); 489167249Snjl 490149450Sume ACPI_DEBUG_PRINT((ACPI_DB_VALUES, "got %d.%dC\n", TZ_KELVTOC(temp))); 491149450Sume sc->tz_temperature = temp; 492149450Sume return (TRUE); 493149450Sume} 494149450Sume 495149450Sume/* 49678915Smsmith * Evaluate the condition of a thermal zone, take appropriate actions. 49778915Smsmith */ 49871874Smsmithstatic void 499119529Snjlacpi_tz_monitor(void *Context) 50071874Smsmith{ 501119529Snjl struct acpi_tz_softc *sc; 502119529Snjl struct timespec curtime; 50379283Smsmith int temp; 50478915Smsmith int i; 50579283Smsmith int newactive, newflags; 50670271Stakawata 50796926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 50870271Stakawata 509119529Snjl sc = (struct acpi_tz_softc *)Context; 51088420Siwasaki 511119529Snjl /* Get the current temperature. */ 512149450Sume if (!acpi_tz_get_temperature(sc)) { 51378915Smsmith /* XXX disable zone? go to max cooling? */ 514133624Snjl return_VOID; 51571874Smsmith } 516149450Sume temp = sc->tz_temperature; 51788420Siwasaki 51878915Smsmith /* 51978915Smsmith * Work out what we ought to be doing right now. 52079283Smsmith * 52179283Smsmith * Note that the _ACx levels sort from hot to cold. 52278915Smsmith */ 52379283Smsmith newactive = TZ_ACTIVE_NONE; 52479375Smsmith for (i = TZ_NUMLEVELS - 1; i >= 0; i--) { 525245266Smav if (sc->tz_zone.ac[i] != -1 && temp >= sc->tz_zone.ac[i]) 52679283Smsmith newactive = i; 52779375Smsmith } 52879283Smsmith 52985699Siwasaki /* 53085699Siwasaki * We are going to get _ACx level down (colder side), but give a guaranteed 53185699Siwasaki * minimum cooling run time if requested. 53285699Siwasaki */ 53385699Siwasaki if (acpi_tz_min_runtime > 0 && sc->tz_active != TZ_ACTIVE_NONE && 534178506Srpaulo sc->tz_active != TZ_ACTIVE_UNKNOWN && 53585699Siwasaki (newactive == TZ_ACTIVE_NONE || newactive > sc->tz_active)) { 536119529Snjl 53785699Siwasaki getnanotime(&curtime); 53885699Siwasaki timespecsub(&curtime, &sc->tz_cooling_started); 539119529Snjl if (curtime.tv_sec < acpi_tz_min_runtime) 54085699Siwasaki newactive = sc->tz_active; 54185699Siwasaki } 54285699Siwasaki 543119529Snjl /* Handle user override of active mode */ 544176327Srpaulo if (sc->tz_requested != TZ_ACTIVE_NONE && (newactive == TZ_ACTIVE_NONE 545176327Srpaulo || sc->tz_requested < newactive)) 54679375Smsmith newactive = sc->tz_requested; 54778915Smsmith 54879375Smsmith /* update temperature-related flags */ 54979375Smsmith newflags = TZ_THFLAG_NONE; 550124439Snjl if (sc->tz_zone.psv != -1 && temp >= sc->tz_zone.psv) 55179375Smsmith newflags |= TZ_THFLAG_PSV; 552124439Snjl if (sc->tz_zone.hot != -1 && temp >= sc->tz_zone.hot) 55379375Smsmith newflags |= TZ_THFLAG_HOT; 554124439Snjl if (sc->tz_zone.crt != -1 && temp >= sc->tz_zone.crt) 55579375Smsmith newflags |= TZ_THFLAG_CRT; 55679375Smsmith 557119529Snjl /* If the active cooling state has changed, we have to switch things. */ 558178506Srpaulo if (sc->tz_active == TZ_ACTIVE_UNKNOWN) { 559178506Srpaulo /* 560178506Srpaulo * We don't know which cooling device is on or off, 561178506Srpaulo * so stop them all, because we now know which 562178506Srpaulo * should be on (if any). 563178506Srpaulo */ 564178506Srpaulo for (i = 0; i < TZ_NUMLEVELS; i++) { 565178506Srpaulo if (sc->tz_zone.al[i].Pointer != NULL) { 566178506Srpaulo acpi_ForeachPackageObject( 567178506Srpaulo (ACPI_OBJECT *)sc->tz_zone.al[i].Pointer, 568178506Srpaulo acpi_tz_switch_cooler_off, sc); 569178506Srpaulo } 570178506Srpaulo } 571178506Srpaulo /* now we know that all devices are off */ 572178506Srpaulo sc->tz_active = TZ_ACTIVE_NONE; 573178506Srpaulo } 574178506Srpaulo 57579283Smsmith if (newactive != sc->tz_active) { 576241538Savg /* Turn off unneeded cooling devices that are on, if any are */ 577241538Savg for (i = TZ_ACTIVE_LEVEL(sc->tz_active); 578241538Savg i < TZ_ACTIVE_LEVEL(newactive); i++) { 579119529Snjl acpi_ForeachPackageObject( 580241538Savg (ACPI_OBJECT *)sc->tz_zone.al[i].Pointer, 581119529Snjl acpi_tz_switch_cooler_off, sc); 582241538Savg } 583119529Snjl /* Turn on cooling devices that are required, if any are */ 584241538Savg for (i = TZ_ACTIVE_LEVEL(sc->tz_active) - 1; 585241538Savg i >= TZ_ACTIVE_LEVEL(newactive); i--) { 586119529Snjl acpi_ForeachPackageObject( 587241538Savg (ACPI_OBJECT *)sc->tz_zone.al[i].Pointer, 588119529Snjl acpi_tz_switch_cooler_on, sc); 589119529Snjl } 590241538Savg 59186552Siwasaki ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 592119529Snjl "switched from %s to %s: %d.%dC\n", 593119529Snjl acpi_tz_aclevel_string(sc->tz_active), 594119529Snjl acpi_tz_aclevel_string(newactive), TZ_KELVTOC(temp)); 59579283Smsmith sc->tz_active = newactive; 596142195Snjl getnanotime(&sc->tz_cooling_started); 59779283Smsmith } 59878915Smsmith 599119529Snjl /* XXX (de)activate any passive cooling that may be required. */ 60078915Smsmith 60178915Smsmith /* 602125335Snjl * If the temperature is at _HOT or _CRT, increment our event count. 603125335Snjl * If it has occurred enough times, shutdown the system. This is 604125335Snjl * needed because some systems will report an invalid high temperature 605125335Snjl * for one poll cycle. It is suspected this is due to the embedded 606125335Snjl * controller timing out. A typical value is 138C for one cycle on 607125335Snjl * a system that is otherwise 65C. 608125366Snjl * 609125366Snjl * If we're almost at that threshold, notify the user through devd(8). 61078915Smsmith */ 611125335Snjl if ((newflags & (TZ_THFLAG_HOT | TZ_THFLAG_CRT)) != 0) { 612125366Snjl sc->tz_validchecks++; 613125366Snjl if (sc->tz_validchecks == TZ_VALIDCHECKS) { 614125335Snjl device_printf(sc->tz_dev, 615125335Snjl "WARNING - current temperature (%d.%dC) exceeds safe limits\n", 616125335Snjl TZ_KELVTOC(sc->tz_temperature)); 617125335Snjl shutdown_nice(RB_POWEROFF); 618125366Snjl } else if (sc->tz_validchecks == TZ_NOTIFYCOUNT) 619125366Snjl acpi_UserNotify("Thermal", sc->tz_handle, TZ_NOTIFY_CRITICAL); 620125335Snjl } else { 621125335Snjl sc->tz_validchecks = 0; 62278915Smsmith } 62379375Smsmith sc->tz_thflags = newflags; 62478915Smsmith 62571874Smsmith return_VOID; 62671874Smsmith} 62770271Stakawata 62878915Smsmith/* 629148138Sume * Given an object, verify that it's a reference to a device of some sort, 63078915Smsmith * and try to switch it off. 63178915Smsmith */ 63278915Smsmithstatic void 63378915Smsmithacpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg) 63478915Smsmith{ 635128047Snjl ACPI_HANDLE cooler; 63678915Smsmith 63796926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 63878915Smsmith 639128047Snjl cooler = acpi_GetReference(NULL, obj); 640128047Snjl if (cooler == NULL) { 641128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get handle\n")); 642128047Snjl return_VOID; 643128047Snjl } 644102470Siwasaki 645128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s off\n", 646128047Snjl acpi_name(cooler))); 647128150Snjl acpi_pwr_switch_consumer(cooler, ACPI_STATE_D3); 648119529Snjl 64979375Smsmith return_VOID; 65078915Smsmith} 65178915Smsmith 65278915Smsmith/* 653148138Sume * Given an object, verify that it's a reference to a device of some sort, 65478915Smsmith * and try to switch it on. 65578915Smsmith * 656128047Snjl * XXX replication of off/on function code is bad. 65778915Smsmith */ 65878915Smsmithstatic void 65978915Smsmithacpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg) 66078915Smsmith{ 66178915Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg; 66278999Smsmith ACPI_HANDLE cooler; 66379375Smsmith ACPI_STATUS status; 664148138Sume 66596926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 66678915Smsmith 667128047Snjl cooler = acpi_GetReference(NULL, obj); 668128047Snjl if (cooler == NULL) { 669128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get handle\n")); 670128047Snjl return_VOID; 671128047Snjl } 672102470Siwasaki 673128047Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s on\n", 674128047Snjl acpi_name(cooler))); 675128047Snjl status = acpi_pwr_switch_consumer(cooler, ACPI_STATE_D0); 676128047Snjl if (ACPI_FAILURE(status)) { 677128047Snjl ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 678128047Snjl "failed to activate %s - %s\n", acpi_name(cooler), 679128047Snjl AcpiFormatException(status)); 68078915Smsmith } 681119529Snjl 682119529Snjl return_VOID; 68378915Smsmith} 68478915Smsmith 68578915Smsmith/* 68678915Smsmith * Read/debug-print a parameter, default it to -1. 68778915Smsmith */ 68878915Smsmithstatic void 68978915Smsmithacpi_tz_getparam(struct acpi_tz_softc *sc, char *node, int *data) 69078915Smsmith{ 69178915Smsmith 69296926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 69378915Smsmith 694126560Snjl if (ACPI_FAILURE(acpi_GetInteger(sc->tz_handle, node, data))) { 69578915Smsmith *data = -1; 69678915Smsmith } else { 697119529Snjl ACPI_DEBUG_PRINT((ACPI_DB_VALUES, "%s.%s = %d\n", 698119529Snjl acpi_name(sc->tz_handle), node, *data)); 69978915Smsmith } 700119529Snjl 701148138Sume return_VOID; 70278915Smsmith} 70379283Smsmith 70479283Smsmith/* 70579283Smsmith * Sanity-check a temperature value. Assume that setpoints 706167249Snjl * should be between 0C and 200C. 70779283Smsmith */ 70879283Smsmithstatic void 70979283Smsmithacpi_tz_sanity(struct acpi_tz_softc *sc, int *val, char *what) 71079283Smsmith{ 711167249Snjl if (*val != -1 && (*val < TZ_ZEROC || *val > TZ_ZEROC + 2000)) { 712255077Sdumbbell /* 713255077Sdumbbell * If the value we are checking is _TMP, warn the user only 714255077Sdumbbell * once. This avoids spamming messages if, for instance, the 715255077Sdumbbell * sensor is broken and always returns an invalid temperature. 716255077Sdumbbell * 717255077Sdumbbell * This is only done for _TMP; other values always emit a 718255077Sdumbbell * warning. 719255077Sdumbbell */ 720255077Sdumbbell if (what != acpi_tz_tmp_name || !sc->tz_insane_tmp_notified) { 721255077Sdumbbell device_printf(sc->tz_dev, "%s value is absurd, ignored (%d.%dC)\n", 722255077Sdumbbell what, TZ_KELVTOC(*val)); 723255077Sdumbbell 724255077Sdumbbell /* Don't warn the user again if the read value doesn't improve. */ 725255077Sdumbbell if (what == acpi_tz_tmp_name) 726255077Sdumbbell sc->tz_insane_tmp_notified = 1; 727255077Sdumbbell } 72879283Smsmith *val = -1; 729255077Sdumbbell return; 73079283Smsmith } 731255077Sdumbbell 732255077Sdumbbell /* This value is correct. Warn if it's incorrect again. */ 733255077Sdumbbell if (what == acpi_tz_tmp_name) 734255077Sdumbbell sc->tz_insane_tmp_notified = 0; 73579283Smsmith} 73679375Smsmith 73779375Smsmith/* 73879375Smsmith * Respond to a sysctl on the active state node. 739148138Sume */ 74079375Smsmithstatic int 74179375Smsmithacpi_tz_active_sysctl(SYSCTL_HANDLER_ARGS) 74279375Smsmith{ 74379375Smsmith struct acpi_tz_softc *sc; 74479375Smsmith int active; 74579375Smsmith int error; 74679375Smsmith 74779375Smsmith sc = (struct acpi_tz_softc *)oidp->oid_arg1; 74879375Smsmith active = sc->tz_active; 74979375Smsmith error = sysctl_handle_int(oidp, &active, 0, req); 75079375Smsmith 751119529Snjl /* Error or no new value */ 752119529Snjl if (error != 0 || req->newptr == NULL) 753133624Snjl return (error); 754133624Snjl if (active < -1 || active >= TZ_NUMLEVELS) 755133624Snjl return (EINVAL); 75679375Smsmith 757119529Snjl /* Set new preferred level and re-switch */ 75879375Smsmith sc->tz_requested = active; 759133624Snjl acpi_tz_signal(sc, 0); 760133624Snjl return (0); 76179375Smsmith} 76279375Smsmith 763148138Sumestatic int 764148138Sumeacpi_tz_cooling_sysctl(SYSCTL_HANDLER_ARGS) 765148138Sume{ 766148138Sume struct acpi_tz_softc *sc; 767148138Sume int enabled, error; 768148138Sume 769148138Sume sc = (struct acpi_tz_softc *)oidp->oid_arg1; 770148138Sume enabled = sc->tz_cooling_enabled; 771148138Sume error = sysctl_handle_int(oidp, &enabled, 0, req); 772148138Sume 773148138Sume /* Error or no new value */ 774148138Sume if (error != 0 || req->newptr == NULL) 775148138Sume return (error); 776148138Sume if (enabled != TRUE && enabled != FALSE) 777148138Sume return (EINVAL); 778148138Sume 779148138Sume if (enabled) { 780148138Sume if (acpi_tz_cooling_is_available(sc)) 781148138Sume error = acpi_tz_cooling_thread_start(sc); 782148138Sume else 783148138Sume error = ENODEV; 784148138Sume if (error) 785148138Sume enabled = FALSE; 786148138Sume } 787148138Sume sc->tz_cooling_enabled = enabled; 788148138Sume return (error); 789148138Sume} 790148138Sume 791160657Snjlstatic int 792160657Snjlacpi_tz_temp_sysctl(SYSCTL_HANDLER_ARGS) 793160657Snjl{ 794160657Snjl struct acpi_tz_softc *sc; 795160657Snjl int temp, *temp_ptr; 796160657Snjl int error; 797160657Snjl 798160657Snjl sc = oidp->oid_arg1; 799299126Sjkim temp_ptr = (int *)(void *)(uintptr_t)((uintptr_t)sc + oidp->oid_arg2); 800160657Snjl temp = *temp_ptr; 801160657Snjl error = sysctl_handle_int(oidp, &temp, 0, req); 802160657Snjl 803160657Snjl /* Error or no new value */ 804160657Snjl if (error != 0 || req->newptr == NULL) 805160657Snjl return (error); 806160657Snjl 807160657Snjl /* Only allow changing settings if override is set. */ 808160657Snjl if (!acpi_tz_override) 809160657Snjl return (EPERM); 810160657Snjl 811160657Snjl /* Check user-supplied value for sanity. */ 812160657Snjl acpi_tz_sanity(sc, &temp, "user-supplied temp"); 813160657Snjl if (temp == -1) 814160657Snjl return (EINVAL); 815160657Snjl 816160657Snjl *temp_ptr = temp; 817160657Snjl return (0); 818160657Snjl} 819160657Snjl 820174889Sumestatic int 821174889Sumeacpi_tz_passive_sysctl(SYSCTL_HANDLER_ARGS) 822174889Sume{ 823174889Sume struct acpi_tz_softc *sc; 824174889Sume int val, *val_ptr; 825174889Sume int error; 826174889Sume 827174889Sume sc = oidp->oid_arg1; 828299126Sjkim val_ptr = (int *)(void *)(uintptr_t)((uintptr_t)sc + oidp->oid_arg2); 829174889Sume val = *val_ptr; 830174889Sume error = sysctl_handle_int(oidp, &val, 0, req); 831174889Sume 832174889Sume /* Error or no new value */ 833174889Sume if (error != 0 || req->newptr == NULL) 834174889Sume return (error); 835174889Sume 836174889Sume /* Only allow changing settings if override is set. */ 837174889Sume if (!acpi_tz_override) 838174889Sume return (EPERM); 839174889Sume 840174889Sume *val_ptr = val; 841174889Sume return (0); 842174889Sume} 843174889Sume 84478915Smsmithstatic void 84571874Smsmithacpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context) 84671874Smsmith{ 84778915Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)context; 84878915Smsmith 84996926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 85070271Stakawata 851133624Snjl switch (notify) { 85278915Smsmith case TZ_NOTIFY_TEMPERATURE: 853119529Snjl /* Temperature change occurred */ 854133624Snjl acpi_tz_signal(sc, 0); 85578915Smsmith break; 85678915Smsmith case TZ_NOTIFY_DEVICES: 85778915Smsmith case TZ_NOTIFY_LEVELS: 858119529Snjl /* Zone devices/setpoints changed */ 859133624Snjl acpi_tz_signal(sc, TZ_FLAG_GETSETTINGS); 86078915Smsmith break; 86178915Smsmith default: 86286552Siwasaki ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 863119529Snjl "unknown Notify event 0x%x\n", notify); 86478915Smsmith break; 86571874Smsmith } 866119529Snjl 867121493Snjl acpi_UserNotify("Thermal", h, notify); 868121493Snjl 86971874Smsmith return_VOID; 87071874Smsmith} 87170271Stakawata 872133624Snjlstatic void 873133624Snjlacpi_tz_signal(struct acpi_tz_softc *sc, int flags) 874133624Snjl{ 875133624Snjl ACPI_LOCK(thermal); 876133624Snjl sc->tz_flags |= flags; 877133624Snjl ACPI_UNLOCK(thermal); 878133624Snjl wakeup(&acpi_tz_proc); 879133624Snjl} 880133624Snjl 88178915Smsmith/* 882134909Snjl * Notifies can be generated asynchronously but have also been seen to be 883134909Snjl * triggered by other thermal methods. One system generates a notify of 884134909Snjl * 0x81 when the fan is turned on or off. Another generates it when _SCP 885134909Snjl * is called. To handle these situations, we check the zone via 886134909Snjl * acpi_tz_monitor() before evaluating changes to setpoints or the cooling 887134909Snjl * policy. 88878915Smsmith */ 88978915Smsmithstatic void 890133624Snjlacpi_tz_timeout(struct acpi_tz_softc *sc, int flags) 89178915Smsmith{ 892134909Snjl 893134909Snjl /* Check the current temperature and take action based on it */ 894134909Snjl acpi_tz_monitor(sc); 895134909Snjl 896133624Snjl /* If requested, get the power profile settings. */ 897133624Snjl if (flags & TZ_FLAG_GETPROFILE) 898133624Snjl acpi_tz_power_profile(sc); 89979375Smsmith 900134909Snjl /* 901134909Snjl * If requested, check for new devices/setpoints. After finding them, 902134909Snjl * check if we need to switch fans based on the new values. 903134909Snjl */ 904134909Snjl if (flags & TZ_FLAG_GETSETTINGS) { 905133624Snjl acpi_tz_establish(sc); 906134909Snjl acpi_tz_monitor(sc); 907134909Snjl } 90878915Smsmith 90978915Smsmith /* XXX passive cooling actions? */ 91078915Smsmith} 91179375Smsmith 91279375Smsmith/* 91379375Smsmith * System power profile may have changed; fetch and notify the 91479375Smsmith * thermal zone accordingly. 91579375Smsmith * 91679375Smsmith * Since this can be called from an arbitrary eventhandler, it needs 91779375Smsmith * to get the ACPI lock itself. 91879375Smsmith */ 91979375Smsmithstatic void 92091640Siwasakiacpi_tz_power_profile(void *arg) 92179375Smsmith{ 92279375Smsmith ACPI_STATUS status; 92379375Smsmith struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg; 92491640Siwasaki int state; 92579375Smsmith 92691640Siwasaki state = power_profile_get_state(); 927119529Snjl if (state != POWER_PROFILE_PERFORMANCE && state != POWER_PROFILE_ECONOMY) 928119529Snjl return; 92991640Siwasaki 93079375Smsmith /* check that we haven't decided there's no _SCP method */ 931119529Snjl if ((sc->tz_flags & TZ_FLAG_NO_SCP) == 0) { 93279375Smsmith 933119529Snjl /* Call _SCP to set the new profile */ 934148138Sume status = acpi_SetInteger(sc->tz_handle, "_SCP", 935126560Snjl (state == POWER_PROFILE_PERFORMANCE) ? 0 : 1); 936119529Snjl if (ACPI_FAILURE(status)) { 93779385Smsmith if (status != AE_NOT_FOUND) 938119529Snjl ACPI_VPRINT(sc->tz_dev, 939119529Snjl acpi_device_get_parent_softc(sc->tz_dev), 940119529Snjl "can't evaluate %s._SCP - %s\n", 941119529Snjl acpi_name(sc->tz_handle), 942119529Snjl AcpiFormatException(status)); 94379375Smsmith sc->tz_flags |= TZ_FLAG_NO_SCP; 94479375Smsmith } else { 945119529Snjl /* We have to re-evaluate the entire zone now */ 946133624Snjl acpi_tz_signal(sc, TZ_FLAG_GETSETTINGS); 94779375Smsmith } 94879375Smsmith } 94979375Smsmith} 95079375Smsmith 95191126Smsmith/* 95291126Smsmith * Thermal zone monitor thread. 95391126Smsmith */ 95491126Smsmithstatic void 95591126Smsmithacpi_tz_thread(void *arg) 95691126Smsmith{ 95791126Smsmith device_t *devs; 95891126Smsmith int devcount, i; 959133624Snjl int flags; 960133624Snjl struct acpi_tz_softc **sc; 96191126Smsmith 96296926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 96391126Smsmith 96491126Smsmith devs = NULL; 96591126Smsmith devcount = 0; 966133624Snjl sc = NULL; 96791126Smsmith 96891126Smsmith for (;;) { 969133624Snjl /* If the number of devices has changed, re-evaluate. */ 970175014Sjhb if (devclass_get_count(acpi_tz_devclass) != devcount) { 971133624Snjl if (devs != NULL) { 972133624Snjl free(devs, M_TEMP); 973133624Snjl free(sc, M_TEMP); 974133624Snjl } 975133624Snjl devclass_get_devices(acpi_tz_devclass, &devs, &devcount); 976133624Snjl sc = malloc(sizeof(struct acpi_tz_softc *) * devcount, M_TEMP, 977133624Snjl M_WAITOK | M_ZERO); 978133624Snjl for (i = 0; i < devcount; i++) 979133624Snjl sc[i] = device_get_softc(devs[i]); 980133624Snjl } 98191126Smsmith 982133624Snjl /* Check for temperature events and act on them. */ 983133624Snjl for (i = 0; i < devcount; i++) { 984133624Snjl ACPI_LOCK(thermal); 985133624Snjl flags = sc[i]->tz_flags; 986133624Snjl sc[i]->tz_flags &= TZ_FLAG_NO_SCP; 987133624Snjl ACPI_UNLOCK(thermal); 988133624Snjl acpi_tz_timeout(sc[i], flags); 989133624Snjl } 99091215Smsmith 991133624Snjl /* If more work to do, don't go to sleep yet. */ 992133624Snjl ACPI_LOCK(thermal); 993133624Snjl for (i = 0; i < devcount; i++) { 994133624Snjl if (sc[i]->tz_flags & ~TZ_FLAG_NO_SCP) 995133624Snjl break; 996133624Snjl } 99791126Smsmith 998133624Snjl /* 999133624Snjl * If we have no more work, sleep for a while, setting PDROP so that 1000133624Snjl * the mutex will not be reacquired. Otherwise, drop the mutex and 1001133624Snjl * loop to handle more events. 1002133624Snjl */ 1003133624Snjl if (i == devcount) 1004133624Snjl msleep(&acpi_tz_proc, &thermal_mutex, PZERO | PDROP, "tzpoll", 1005133624Snjl hz * acpi_tz_polling_rate); 1006133624Snjl else 1007133624Snjl ACPI_UNLOCK(thermal); 100891126Smsmith } 100991126Smsmith} 1010148138Sume 1011148138Sumestatic int 1012148138Sumeacpi_tz_cpufreq_restore(struct acpi_tz_softc *sc) 1013148138Sume{ 1014148138Sume device_t dev; 1015148138Sume int error; 1016148138Sume 1017148138Sume if (!sc->tz_cooling_updated) 1018148138Sume return (0); 1019148138Sume if ((dev = devclass_get_device(devclass_find("cpufreq"), 0)) == NULL) 1020148138Sume return (ENXIO); 1021148138Sume ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 1022149201Sume "temperature %d.%dC: resuming previous clock speed (%d MHz)\n", 1023149201Sume TZ_KELVTOC(sc->tz_temperature), sc->tz_cooling_saved_freq); 1024148138Sume error = CPUFREQ_SET(dev, NULL, CPUFREQ_PRIO_KERN); 1025148138Sume if (error == 0) 1026148138Sume sc->tz_cooling_updated = FALSE; 1027148138Sume return (error); 1028148138Sume} 1029148138Sume 1030148138Sumestatic int 1031148138Sumeacpi_tz_cpufreq_update(struct acpi_tz_softc *sc, int req) 1032148138Sume{ 1033148138Sume device_t dev; 1034148138Sume struct cf_level *levels; 1035148138Sume int num_levels, error, freq, desired_freq, perf, i; 1036148138Sume 1037148138Sume levels = malloc(CPUFREQ_MAX_LEVELS * sizeof(*levels), M_TEMP, M_NOWAIT); 1038148138Sume if (levels == NULL) 1039148138Sume return (ENOMEM); 1040148138Sume 1041148138Sume /* 1042148138Sume * Find the main device, cpufreq0. We don't yet support independent 1043148138Sume * CPU frequency control on SMP. 1044148138Sume */ 1045148138Sume if ((dev = devclass_get_device(devclass_find("cpufreq"), 0)) == NULL) { 1046148138Sume error = ENXIO; 1047148138Sume goto out; 1048148138Sume } 1049148138Sume 1050148138Sume /* Get the current frequency. */ 1051148138Sume error = CPUFREQ_GET(dev, &levels[0]); 1052148138Sume if (error) 1053148138Sume goto out; 1054148138Sume freq = levels[0].total_set.freq; 1055148138Sume 1056148138Sume /* Get the current available frequency levels. */ 1057148138Sume num_levels = CPUFREQ_MAX_LEVELS; 1058148138Sume error = CPUFREQ_LEVELS(dev, levels, &num_levels); 1059148138Sume if (error) { 1060148138Sume if (error == E2BIG) 1061148138Sume printf("cpufreq: need to increase CPUFREQ_MAX_LEVELS\n"); 1062148138Sume goto out; 1063148138Sume } 1064148138Sume 1065148138Sume /* Calculate the desired frequency as a percent of the max frequency. */ 1066148138Sume perf = 100 * freq / levels[0].total_set.freq - req; 1067148138Sume if (perf < 0) 1068148138Sume perf = 0; 1069148138Sume else if (perf > 100) 1070148138Sume perf = 100; 1071148138Sume desired_freq = levels[0].total_set.freq * perf / 100; 1072148138Sume 1073149201Sume if (desired_freq < freq) { 1074148138Sume /* Find the closest available frequency, rounding down. */ 1075148138Sume for (i = 0; i < num_levels; i++) 1076148138Sume if (levels[i].total_set.freq <= desired_freq) 1077148138Sume break; 1078148138Sume 1079148138Sume /* If we didn't find a relevant setting, use the lowest. */ 1080148138Sume if (i == num_levels) 1081148138Sume i--; 1082148138Sume } else { 1083149201Sume /* If we didn't decrease frequency yet, don't increase it. */ 1084149201Sume if (!sc->tz_cooling_updated) { 1085149201Sume sc->tz_cooling_active = FALSE; 1086149201Sume goto out; 1087149201Sume } 1088149201Sume 1089149201Sume /* Use saved cpu frequency as maximum value. */ 1090149201Sume if (desired_freq > sc->tz_cooling_saved_freq) 1091149201Sume desired_freq = sc->tz_cooling_saved_freq; 1092149201Sume 1093148138Sume /* Find the closest available frequency, rounding up. */ 1094148138Sume for (i = num_levels - 1; i >= 0; i--) 1095148138Sume if (levels[i].total_set.freq >= desired_freq) 1096148138Sume break; 1097148138Sume 1098148138Sume /* If we didn't find a relevant setting, use the highest. */ 1099148138Sume if (i == -1) 1100148138Sume i++; 1101148138Sume 1102149201Sume /* If we're going to the highest frequency, restore the old setting. */ 1103149201Sume if (i == 0 || desired_freq == sc->tz_cooling_saved_freq) { 1104149201Sume error = acpi_tz_cpufreq_restore(sc); 1105149201Sume if (error == 0) 1106149201Sume sc->tz_cooling_active = FALSE; 1107149201Sume goto out; 1108149201Sume } 1109148138Sume } 1110148138Sume 1111148138Sume /* If we are going to a new frequency, activate it. */ 1112148138Sume if (levels[i].total_set.freq != freq) { 1113148138Sume ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), 1114148138Sume "temperature %d.%dC: %screasing clock speed " 1115148138Sume "from %d MHz to %d MHz\n", 1116148138Sume TZ_KELVTOC(sc->tz_temperature), 1117148138Sume (freq > levels[i].total_set.freq) ? "de" : "in", 1118148138Sume freq, levels[i].total_set.freq); 1119148138Sume error = CPUFREQ_SET(dev, &levels[i], CPUFREQ_PRIO_KERN); 1120149201Sume if (error == 0 && !sc->tz_cooling_updated) { 1121149201Sume sc->tz_cooling_saved_freq = freq; 1122148138Sume sc->tz_cooling_updated = TRUE; 1123149201Sume } 1124148138Sume } 1125148138Sume 1126148138Sumeout: 1127148138Sume if (levels) 1128148138Sume free(levels, M_TEMP); 1129148138Sume return (error); 1130148138Sume} 1131148138Sume 1132148138Sume/* 1133148138Sume * Passive cooling thread; monitors current temperature according to the 1134148138Sume * cooling interval and calculates whether to scale back CPU frequency. 1135148138Sume */ 1136148138Sumestatic void 1137148138Sumeacpi_tz_cooling_thread(void *arg) 1138148138Sume{ 1139148138Sume struct acpi_tz_softc *sc; 1140149450Sume int error, perf, curr_temp, prev_temp; 1141148138Sume 1142148138Sume ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 1143148138Sume 1144148138Sume sc = (struct acpi_tz_softc *)arg; 1145148138Sume 1146149450Sume prev_temp = sc->tz_temperature; 1147148138Sume while (sc->tz_cooling_enabled) { 1148149450Sume if (sc->tz_cooling_active) 1149149450Sume (void)acpi_tz_get_temperature(sc); 1150149450Sume curr_temp = sc->tz_temperature; 1151149450Sume if (curr_temp >= sc->tz_zone.psv) 1152148138Sume sc->tz_cooling_active = TRUE; 1153148138Sume if (sc->tz_cooling_active) { 1154149450Sume perf = sc->tz_zone.tc1 * (curr_temp - prev_temp) + 1155149450Sume sc->tz_zone.tc2 * (curr_temp - sc->tz_zone.psv); 1156148138Sume perf /= 10; 1157148138Sume 1158148138Sume if (perf != 0) { 1159148138Sume error = acpi_tz_cpufreq_update(sc, perf); 1160148138Sume 1161148138Sume /* 1162148138Sume * If error and not simply a higher priority setting was 1163148138Sume * active, disable cooling. 1164148138Sume */ 1165148138Sume if (error != 0 && error != EPERM) { 1166148138Sume device_printf(sc->tz_dev, 1167148138Sume "failed to set new freq, disabling passive cooling\n"); 1168148138Sume sc->tz_cooling_enabled = FALSE; 1169148138Sume } 1170148138Sume } 1171148138Sume } 1172149450Sume prev_temp = curr_temp; 1173148138Sume tsleep(&sc->tz_cooling_proc, PZERO, "cooling", 1174148138Sume hz * sc->tz_zone.tsp / 10); 1175148138Sume } 1176148138Sume if (sc->tz_cooling_active) { 1177148138Sume acpi_tz_cpufreq_restore(sc); 1178148138Sume sc->tz_cooling_active = FALSE; 1179148138Sume } 1180148703Sume sc->tz_cooling_proc = NULL; 1181148138Sume ACPI_LOCK(thermal); 1182148703Sume sc->tz_cooling_proc_running = FALSE; 1183148138Sume ACPI_UNLOCK(thermal); 1184172836Sjulian kproc_exit(0); 1185148138Sume} 1186148138Sume 1187148138Sume/* 1188148138Sume * TODO: We ignore _PSL (list of cooling devices) since cpufreq enumerates 1189148138Sume * all CPUs for us. However, it's possible in the future _PSL will 1190148138Sume * reference non-CPU devices so we may want to support it then. 1191148138Sume */ 1192148138Sumestatic int 1193148138Sumeacpi_tz_cooling_is_available(struct acpi_tz_softc *sc) 1194148138Sume{ 1195148138Sume return (sc->tz_zone.tc1 != -1 && sc->tz_zone.tc2 != -1 && 1196148138Sume sc->tz_zone.tsp != -1 && sc->tz_zone.tsp != 0 && 1197148138Sume sc->tz_zone.psv != -1); 1198148138Sume} 1199148138Sume 1200148138Sumestatic int 1201148138Sumeacpi_tz_cooling_thread_start(struct acpi_tz_softc *sc) 1202148138Sume{ 1203148138Sume int error; 1204148138Sume 1205148703Sume ACPI_LOCK(thermal); 1206148703Sume if (sc->tz_cooling_proc_running) { 1207148703Sume ACPI_UNLOCK(thermal); 1208148703Sume return (0); 1209148703Sume } 1210148703Sume sc->tz_cooling_proc_running = TRUE; 1211148703Sume ACPI_UNLOCK(thermal); 1212148138Sume error = 0; 1213148138Sume if (sc->tz_cooling_proc == NULL) { 1214209062Savg error = kproc_create(acpi_tz_cooling_thread, sc, 1215209062Savg &sc->tz_cooling_proc, RFHIGHPID, 0, "acpi_cooling%d", 1216148138Sume device_get_unit(sc->tz_dev)); 1217148703Sume if (error != 0) { 1218148138Sume device_printf(sc->tz_dev, "could not create thread - %d", error); 1219148703Sume ACPI_LOCK(thermal); 1220148703Sume sc->tz_cooling_proc_running = FALSE; 1221148703Sume ACPI_UNLOCK(thermal); 1222148703Sume } 1223148138Sume } 1224148138Sume return (error); 1225148138Sume} 1226