The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/acpica/acpi_thermal.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2000, 2001 Michael Smith
    3  * Copyright (c) 2000 BSDi
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 #include <sys/cdefs.h>
   29 __FBSDID("$FreeBSD: releng/5.3/sys/dev/acpica/acpi_thermal.c 135807 2004-09-26 06:39:35Z njl $");
   30 
   31 #include "opt_acpi.h"
   32 #include <sys/param.h>
   33 #include <sys/kernel.h>
   34 #include <sys/bus.h>
   35 #include <sys/kthread.h>
   36 #include <sys/malloc.h>
   37 #include <sys/module.h>
   38 #include <sys/bus.h>
   39 #include <sys/proc.h>
   40 #include <sys/reboot.h>
   41 #include <sys/sysctl.h>
   42 #include <sys/unistd.h>
   43 #include <sys/power.h>
   44 
   45 #include "acpi.h"
   46 #include <dev/acpica/acpivar.h>
   47 
   48 /* Hooks for the ACPI CA debugging infrastructure */
   49 #define _COMPONENT      ACPI_THERMAL
   50 ACPI_MODULE_NAME("THERMAL")
   51 
   52 #define TZ_ZEROC        2732
   53 #define TZ_KELVTOC(x)   (((x) - TZ_ZEROC) / 10), (((x) - TZ_ZEROC) % 10)
   54 
   55 #define TZ_NOTIFY_TEMPERATURE   0x80 /* Temperature changed. */
   56 #define TZ_NOTIFY_LEVELS        0x81 /* Cooling levels changed. */
   57 #define TZ_NOTIFY_DEVICES       0x82 /* Device lists changed. */
   58 #define TZ_NOTIFY_CRITICAL      0xcc /* Fake notify that _CRT/_HOT reached. */
   59 
   60 /* Check for temperature changes every 10 seconds by default */
   61 #define TZ_POLLRATE     10
   62 
   63 /* Make sure the reported temperature is valid for this number of polls. */
   64 #define TZ_VALIDCHECKS  3
   65 
   66 /* Notify the user we will be shutting down in one more poll cycle. */
   67 #define TZ_NOTIFYCOUNT  (TZ_VALIDCHECKS - 1)
   68 
   69 /* ACPI spec defines this */
   70 #define TZ_NUMLEVELS    10
   71 struct acpi_tz_zone {
   72     int         ac[TZ_NUMLEVELS];
   73     ACPI_BUFFER al[TZ_NUMLEVELS];
   74     int         crt;
   75     int         hot;
   76     ACPI_BUFFER psl;
   77     int         psv;
   78     int         tc1;
   79     int         tc2;
   80     int         tsp;
   81     int         tzp;
   82 };
   83 
   84 struct acpi_tz_softc {
   85     device_t                    tz_dev;
   86     ACPI_HANDLE                 tz_handle;      /*Thermal zone handle*/
   87     int                         tz_temperature; /*Current temperature*/
   88     int                         tz_active;      /*Current active cooling*/
   89 #define TZ_ACTIVE_NONE          -1
   90     int                         tz_requested;   /*Minimum active cooling*/
   91     int                         tz_thflags;     /*Current temp-related flags*/
   92 #define TZ_THFLAG_NONE          0
   93 #define TZ_THFLAG_PSV           (1<<0)
   94 #define TZ_THFLAG_HOT           (1<<2)
   95 #define TZ_THFLAG_CRT           (1<<3)    
   96     int                         tz_flags;
   97 #define TZ_FLAG_NO_SCP          (1<<0)          /*No _SCP method*/
   98 #define TZ_FLAG_GETPROFILE      (1<<1)          /*Get power_profile in timeout*/
   99 #define TZ_FLAG_GETSETTINGS     (1<<2)          /*Get devs/setpoints*/
  100     struct timespec             tz_cooling_started;
  101                                         /*Current cooling starting time*/
  102 
  103     struct sysctl_ctx_list      tz_sysctl_ctx;
  104     struct sysctl_oid           *tz_sysctl_tree;
  105     eventhandler_tag            tz_event;
  106 
  107     struct acpi_tz_zone         tz_zone;        /*Thermal zone parameters*/
  108     int                         tz_validchecks;
  109 };
  110 
  111 static int      acpi_tz_probe(device_t dev);
  112 static int      acpi_tz_attach(device_t dev);
  113 static int      acpi_tz_establish(struct acpi_tz_softc *sc);
  114 static void     acpi_tz_monitor(void *Context);
  115 #if 0
  116 static void     acpi_tz_all_off(struct acpi_tz_softc *sc);
  117 #endif
  118 static void     acpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg);
  119 static void     acpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg);
  120 static void     acpi_tz_getparam(struct acpi_tz_softc *sc, char *node,
  121                                  int *data);
  122 static void     acpi_tz_sanity(struct acpi_tz_softc *sc, int *val, char *what);
  123 static int      acpi_tz_active_sysctl(SYSCTL_HANDLER_ARGS);
  124 static void     acpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify,
  125                                        void *context);
  126 static void     acpi_tz_signal(struct acpi_tz_softc *sc, int flags);
  127 static void     acpi_tz_timeout(struct acpi_tz_softc *sc, int flags);
  128 static void     acpi_tz_power_profile(void *arg);
  129 static void     acpi_tz_thread(void *arg);
  130 
  131 static device_method_t acpi_tz_methods[] = {
  132     /* Device interface */
  133     DEVMETHOD(device_probe,     acpi_tz_probe),
  134     DEVMETHOD(device_attach,    acpi_tz_attach),
  135 
  136     {0, 0}
  137 };
  138 
  139 static driver_t acpi_tz_driver = {
  140     "acpi_tz",
  141     acpi_tz_methods,
  142     sizeof(struct acpi_tz_softc),
  143 };
  144 
  145 static devclass_t acpi_tz_devclass;
  146 DRIVER_MODULE(acpi_tz, acpi, acpi_tz_driver, acpi_tz_devclass, 0, 0);
  147 MODULE_DEPEND(acpi_tz, acpi, 1, 1, 1);
  148 
  149 static struct sysctl_ctx_list   acpi_tz_sysctl_ctx;
  150 static struct sysctl_oid        *acpi_tz_sysctl_tree;
  151 
  152 /* Minimum cooling run time */
  153 static int                      acpi_tz_min_runtime = 0;
  154 static int                      acpi_tz_polling_rate = TZ_POLLRATE;
  155 
  156 /* Timezone polling thread */
  157 static struct proc              *acpi_tz_proc;
  158 ACPI_LOCK_DECL(thermal, "ACPI thermal zone");
  159 
  160 static int
  161 acpi_tz_probe(device_t dev)
  162 {
  163     int         result;
  164     
  165     if (acpi_get_type(dev) == ACPI_TYPE_THERMAL && !acpi_disabled("thermal")) {
  166         device_set_desc(dev, "Thermal Zone");
  167         result = -10;
  168     } else
  169         result = ENXIO;
  170     return (result);
  171 }
  172 
  173 static int
  174 acpi_tz_attach(device_t dev)
  175 {
  176     struct acpi_tz_softc        *sc;
  177     struct acpi_softc           *acpi_sc;
  178     int                         error;
  179     char                        oidname[8];
  180 
  181     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  182 
  183     sc = device_get_softc(dev);
  184     sc->tz_dev = dev;
  185     sc->tz_handle = acpi_get_handle(dev);
  186     sc->tz_requested = TZ_ACTIVE_NONE;
  187     sc->tz_active = TZ_ACTIVE_NONE;
  188     sc->tz_thflags = TZ_THFLAG_NONE;
  189 
  190     /*
  191      * Parse the current state of the thermal zone and build control
  192      * structures.  We don't need to worry about interference with the
  193      * control thread since we haven't fully attached this device yet.
  194      */
  195     if ((error = acpi_tz_establish(sc)) != 0)
  196         return (error);
  197 
  198     /*
  199      * Register for any Notify events sent to this zone.
  200      */
  201     AcpiInstallNotifyHandler(sc->tz_handle, ACPI_DEVICE_NOTIFY, 
  202                              acpi_tz_notify_handler, sc);
  203 
  204     /*
  205      * Create our sysctl nodes.
  206      *
  207      * XXX we need a mechanism for adding nodes under ACPI.
  208      */
  209     if (device_get_unit(dev) == 0) {
  210         acpi_sc = acpi_device_get_parent_softc(dev);
  211         sysctl_ctx_init(&acpi_tz_sysctl_ctx);
  212         acpi_tz_sysctl_tree = SYSCTL_ADD_NODE(&acpi_tz_sysctl_ctx,
  213                               SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree),
  214                               OID_AUTO, "thermal", CTLFLAG_RD, 0, "");
  215         SYSCTL_ADD_INT(&acpi_tz_sysctl_ctx,
  216                        SYSCTL_CHILDREN(acpi_tz_sysctl_tree),
  217                        OID_AUTO, "min_runtime", CTLFLAG_RD | CTLFLAG_RW,
  218                        &acpi_tz_min_runtime, 0,
  219                        "minimum cooling run time in sec");
  220         SYSCTL_ADD_INT(&acpi_tz_sysctl_ctx,
  221                        SYSCTL_CHILDREN(acpi_tz_sysctl_tree),
  222                        OID_AUTO, "polling_rate", CTLFLAG_RD | CTLFLAG_RW,
  223                        &acpi_tz_polling_rate, 0, "monitor polling rate");
  224     }
  225     sysctl_ctx_init(&sc->tz_sysctl_ctx);
  226     sprintf(oidname, "tz%d", device_get_unit(dev));
  227     sc->tz_sysctl_tree = SYSCTL_ADD_NODE(&sc->tz_sysctl_ctx,
  228                                          SYSCTL_CHILDREN(acpi_tz_sysctl_tree),
  229                                          OID_AUTO, oidname, CTLFLAG_RD, 0, "");
  230     SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
  231                    OID_AUTO, "temperature", CTLFLAG_RD,
  232                    &sc->tz_temperature, 0, "current thermal zone temperature");
  233     SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
  234                     OID_AUTO, "active", CTLTYPE_INT | CTLFLAG_RW,
  235                     sc, 0, acpi_tz_active_sysctl, "I", "");
  236     
  237     SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
  238                    OID_AUTO, "thermal_flags", CTLFLAG_RD,
  239                    &sc->tz_thflags, 0, "thermal zone flags");
  240     SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
  241                    OID_AUTO, "_PSV", CTLFLAG_RD,
  242                    &sc->tz_zone.psv, 0, "");
  243     SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
  244                    OID_AUTO, "_HOT", CTLFLAG_RD,
  245                    &sc->tz_zone.hot, 0, "");
  246     SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
  247                    OID_AUTO, "_CRT", CTLFLAG_RD,
  248                    &sc->tz_zone.crt, 0, "");
  249     SYSCTL_ADD_OPAQUE(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
  250                       OID_AUTO, "_ACx", CTLFLAG_RD, &sc->tz_zone.ac,
  251                       sizeof(sc->tz_zone.ac), "I", "");
  252 
  253     /*
  254      * Create our thread; we only need one, it will service all of the
  255      * thermal zones.  Register our power profile event handler.
  256      */
  257     sc->tz_event = EVENTHANDLER_REGISTER(power_profile_change,
  258         acpi_tz_power_profile, sc, 0);
  259     if (acpi_tz_proc == NULL) {
  260         error = kthread_create(acpi_tz_thread, NULL, &acpi_tz_proc,
  261             RFHIGHPID, 0, "acpi_thermal");
  262         if (error != 0) {
  263             device_printf(sc->tz_dev, "could not create thread - %d", error);
  264             goto out;
  265         }
  266     }
  267 
  268     /*
  269      * Flag the event handler for a manual invocation by our timeout.
  270      * We defer it like this so that the rest of the subsystem has time
  271      * to come up.  Don't bother evaluating/printing the temperature at
  272      * this point; on many systems it'll be bogus until the EC is running.
  273      */
  274     sc->tz_flags |= TZ_FLAG_GETPROFILE;
  275 
  276 out:
  277     if (error != 0) {
  278         EVENTHANDLER_DEREGISTER(power_profile_change, sc->tz_event);
  279         AcpiRemoveNotifyHandler(sc->tz_handle, ACPI_DEVICE_NOTIFY,
  280             acpi_tz_notify_handler);
  281         sysctl_ctx_free(&sc->tz_sysctl_ctx);
  282     }
  283     return_VALUE (error);
  284 }
  285 
  286 /*
  287  * Parse the current state of this thermal zone and set up to use it.
  288  *
  289  * Note that we may have previous state, which will have to be discarded.
  290  */
  291 static int
  292 acpi_tz_establish(struct acpi_tz_softc *sc)
  293 {
  294     ACPI_OBJECT *obj;
  295     int         i;
  296     char        nbuf[8];
  297     
  298     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  299 
  300     /* Erase any existing state. */
  301     for (i = 0; i < TZ_NUMLEVELS; i++)
  302         if (sc->tz_zone.al[i].Pointer != NULL)
  303             AcpiOsFree(sc->tz_zone.al[i].Pointer);
  304     if (sc->tz_zone.psl.Pointer != NULL)
  305         AcpiOsFree(sc->tz_zone.psl.Pointer);
  306     bzero(&sc->tz_zone, sizeof(sc->tz_zone));
  307 
  308     /* Evaluate thermal zone parameters. */
  309     for (i = 0; i < TZ_NUMLEVELS; i++) {
  310         sprintf(nbuf, "_AC%d", i);
  311         acpi_tz_getparam(sc, nbuf, &sc->tz_zone.ac[i]);
  312         sprintf(nbuf, "_AL%d", i);
  313         sc->tz_zone.al[i].Length = ACPI_ALLOCATE_BUFFER;
  314         sc->tz_zone.al[i].Pointer = NULL;
  315         AcpiEvaluateObject(sc->tz_handle, nbuf, NULL, &sc->tz_zone.al[i]);
  316         obj = (ACPI_OBJECT *)sc->tz_zone.al[i].Pointer;
  317         if (obj != NULL) {
  318             /* Should be a package containing a list of power objects */
  319             if (obj->Type != ACPI_TYPE_PACKAGE) {
  320                 device_printf(sc->tz_dev, "%s has unknown type %d, rejecting\n",
  321                               nbuf, obj->Type);
  322                 return_VALUE (ENXIO);
  323             }
  324         }
  325     }
  326     acpi_tz_getparam(sc, "_CRT", &sc->tz_zone.crt);
  327     acpi_tz_getparam(sc, "_HOT", &sc->tz_zone.hot);
  328     sc->tz_zone.psl.Length = ACPI_ALLOCATE_BUFFER;
  329     sc->tz_zone.psl.Pointer = NULL;
  330     AcpiEvaluateObject(sc->tz_handle, "_PSL", NULL, &sc->tz_zone.psl);
  331     acpi_tz_getparam(sc, "_PSV", &sc->tz_zone.psv);
  332     acpi_tz_getparam(sc, "_TC1", &sc->tz_zone.tc1);
  333     acpi_tz_getparam(sc, "_TC2", &sc->tz_zone.tc2);
  334     acpi_tz_getparam(sc, "_TSP", &sc->tz_zone.tsp);
  335     acpi_tz_getparam(sc, "_TZP", &sc->tz_zone.tzp);
  336 
  337     /*
  338      * Sanity-check the values we've been given.
  339      *
  340      * XXX what do we do about systems that give us the same value for
  341      *     more than one of these setpoints?
  342      */
  343     acpi_tz_sanity(sc, &sc->tz_zone.crt, "_CRT");
  344     acpi_tz_sanity(sc, &sc->tz_zone.hot, "_HOT");
  345     acpi_tz_sanity(sc, &sc->tz_zone.psv, "_PSV");
  346     for (i = 0; i < TZ_NUMLEVELS; i++)
  347         acpi_tz_sanity(sc, &sc->tz_zone.ac[i], "_ACx");
  348 
  349     return_VALUE (0);
  350 }
  351 
  352 static char *aclevel_string[] = {
  353     "NONE", "_AC0", "_AC1", "_AC2", "_AC3", "_AC4",
  354     "_AC5", "_AC6", "_AC7", "_AC8", "_AC9"
  355 };
  356 
  357 static __inline const char *
  358 acpi_tz_aclevel_string(int active)
  359 {
  360     if (active < -1 || active >= TZ_NUMLEVELS)
  361         return (aclevel_string[0]);
  362 
  363     return (aclevel_string[active + 1]);
  364 }
  365 
  366 /*
  367  * Evaluate the condition of a thermal zone, take appropriate actions.
  368  */
  369 static void
  370 acpi_tz_monitor(void *Context)
  371 {
  372     struct acpi_tz_softc *sc;
  373     struct      timespec curtime;
  374     int         temp;
  375     int         i;
  376     int         newactive, newflags;
  377     ACPI_STATUS status;
  378 
  379     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  380 
  381     sc = (struct acpi_tz_softc *)Context;
  382 
  383     /* Get the current temperature. */
  384     status = acpi_GetInteger(sc->tz_handle, "_TMP", &temp);
  385     if (ACPI_FAILURE(status)) {
  386         ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev),
  387             "error fetching current temperature -- %s\n",
  388              AcpiFormatException(status));
  389         /* XXX disable zone? go to max cooling? */
  390         return_VOID;
  391     }
  392 
  393     ACPI_DEBUG_PRINT((ACPI_DB_VALUES, "got %d.%dC\n", TZ_KELVTOC(temp)));
  394     sc->tz_temperature = temp;
  395 
  396     /*
  397      * Work out what we ought to be doing right now.
  398      *
  399      * Note that the _ACx levels sort from hot to cold.
  400      */
  401     newactive = TZ_ACTIVE_NONE;
  402     for (i = TZ_NUMLEVELS - 1; i >= 0; i--) {
  403         if ((sc->tz_zone.ac[i] != -1) && (temp >= sc->tz_zone.ac[i])) {
  404             newactive = i;
  405             if (sc->tz_active != newactive) {
  406                 ACPI_VPRINT(sc->tz_dev,
  407                             acpi_device_get_parent_softc(sc->tz_dev),
  408                             "_AC%d: temperature %d.%d >= setpoint %d.%d\n", i,
  409                             TZ_KELVTOC(temp), TZ_KELVTOC(sc->tz_zone.ac[i]));
  410                 getnanotime(&sc->tz_cooling_started);
  411             }
  412         }
  413     }
  414 
  415     /*
  416      * We are going to get _ACx level down (colder side), but give a guaranteed
  417      * minimum cooling run time if requested.
  418      */
  419     if (acpi_tz_min_runtime > 0 && sc->tz_active != TZ_ACTIVE_NONE &&
  420         (newactive == TZ_ACTIVE_NONE || newactive > sc->tz_active)) {
  421 
  422         getnanotime(&curtime);
  423         timespecsub(&curtime, &sc->tz_cooling_started);
  424         if (curtime.tv_sec < acpi_tz_min_runtime)
  425             newactive = sc->tz_active;
  426     }
  427 
  428     /* Handle user override of active mode */
  429     if (sc->tz_requested != TZ_ACTIVE_NONE && sc->tz_requested < newactive)
  430         newactive = sc->tz_requested;
  431 
  432     /* update temperature-related flags */
  433     newflags = TZ_THFLAG_NONE;
  434     if (sc->tz_zone.psv != -1 && temp >= sc->tz_zone.psv)
  435         newflags |= TZ_THFLAG_PSV;
  436     if (sc->tz_zone.hot != -1 && temp >= sc->tz_zone.hot)
  437         newflags |= TZ_THFLAG_HOT;
  438     if (sc->tz_zone.crt != -1 && temp >= sc->tz_zone.crt)
  439         newflags |= TZ_THFLAG_CRT;
  440 
  441     /* If the active cooling state has changed, we have to switch things. */
  442     if (newactive != sc->tz_active) {
  443         /* Turn off the cooling devices that are on, if any are */
  444         if (sc->tz_active != TZ_ACTIVE_NONE)
  445             acpi_ForeachPackageObject(
  446                 (ACPI_OBJECT *)sc->tz_zone.al[sc->tz_active].Pointer,
  447                 acpi_tz_switch_cooler_off, sc);
  448 
  449         /* Turn on cooling devices that are required, if any are */
  450         if (newactive != TZ_ACTIVE_NONE) {
  451             acpi_ForeachPackageObject(
  452                 (ACPI_OBJECT *)sc->tz_zone.al[newactive].Pointer,
  453                 acpi_tz_switch_cooler_on, sc);
  454         }
  455         ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev),
  456                     "switched from %s to %s: %d.%dC\n",
  457                     acpi_tz_aclevel_string(sc->tz_active),
  458                     acpi_tz_aclevel_string(newactive), TZ_KELVTOC(temp));
  459         sc->tz_active = newactive;
  460     }
  461 
  462     /* XXX (de)activate any passive cooling that may be required. */
  463 
  464     /*
  465      * If the temperature is at _HOT or _CRT, increment our event count.
  466      * If it has occurred enough times, shutdown the system.  This is
  467      * needed because some systems will report an invalid high temperature
  468      * for one poll cycle.  It is suspected this is due to the embedded
  469      * controller timing out.  A typical value is 138C for one cycle on
  470      * a system that is otherwise 65C.
  471      *
  472      * If we're almost at that threshold, notify the user through devd(8).
  473      */
  474     if ((newflags & (TZ_THFLAG_HOT | TZ_THFLAG_CRT)) != 0) {
  475         sc->tz_validchecks++;
  476         if (sc->tz_validchecks == TZ_VALIDCHECKS) {
  477             device_printf(sc->tz_dev,
  478                 "WARNING - current temperature (%d.%dC) exceeds safe limits\n",
  479                 TZ_KELVTOC(sc->tz_temperature));
  480             shutdown_nice(RB_POWEROFF);
  481         } else if (sc->tz_validchecks == TZ_NOTIFYCOUNT)
  482             acpi_UserNotify("Thermal", sc->tz_handle, TZ_NOTIFY_CRITICAL);
  483     } else {
  484         sc->tz_validchecks = 0;
  485     }
  486     sc->tz_thflags = newflags;
  487 
  488     return_VOID;
  489 }
  490 
  491 #if 0
  492 /*
  493  * Turn off all the cooling devices.
  494  */
  495 static void
  496 acpi_tz_all_off(struct acpi_tz_softc *sc)
  497 {
  498     int         i;
  499 
  500     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  501 
  502     /* Scan all the _ALx objects and turn them all off. */
  503     for (i = 0; i < TZ_NUMLEVELS; i++) {
  504         if (sc->tz_zone.al[i].Pointer == NULL)
  505             continue;
  506         acpi_ForeachPackageObject((ACPI_OBJECT *)sc->tz_zone.al[i].Pointer,
  507                                   acpi_tz_switch_cooler_off, sc);
  508     }
  509 
  510     /*
  511      * XXX revert any passive-cooling options.
  512      */
  513 
  514     return_VOID;
  515 }
  516 #endif
  517 
  518 /*
  519  * Given an object, verify that it's a reference to a device of some sort, 
  520  * and try to switch it off.
  521  */
  522 static void
  523 acpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg)
  524 {
  525     ACPI_HANDLE                 cooler;
  526 
  527     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  528 
  529     cooler = acpi_GetReference(NULL, obj);
  530     if (cooler == NULL) {
  531         ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get handle\n"));
  532         return_VOID;
  533     }
  534 
  535     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s off\n",
  536                      acpi_name(cooler)));
  537     acpi_pwr_switch_consumer(cooler, ACPI_STATE_D3);
  538 
  539     return_VOID;
  540 }
  541 
  542 /*
  543  * Given an object, verify that it's a reference to a device of some sort, 
  544  * and try to switch it on.
  545  *
  546  * XXX replication of off/on function code is bad.
  547  */
  548 static void
  549 acpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg)
  550 {
  551     struct acpi_tz_softc        *sc = (struct acpi_tz_softc *)arg;
  552     ACPI_HANDLE                 cooler;
  553     ACPI_STATUS                 status;
  554     
  555     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  556 
  557     cooler = acpi_GetReference(NULL, obj);
  558     if (cooler == NULL) {
  559         ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get handle\n"));
  560         return_VOID;
  561     }
  562 
  563     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s on\n",
  564                      acpi_name(cooler)));
  565     status = acpi_pwr_switch_consumer(cooler, ACPI_STATE_D0);
  566     if (ACPI_FAILURE(status)) {
  567         ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev),
  568                     "failed to activate %s - %s\n", acpi_name(cooler),
  569                     AcpiFormatException(status));
  570     }
  571 
  572     return_VOID;
  573 }
  574 
  575 /*
  576  * Read/debug-print a parameter, default it to -1.
  577  */
  578 static void
  579 acpi_tz_getparam(struct acpi_tz_softc *sc, char *node, int *data)
  580 {
  581 
  582     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  583 
  584     if (ACPI_FAILURE(acpi_GetInteger(sc->tz_handle, node, data))) {
  585         *data = -1;
  586     } else {
  587         ACPI_DEBUG_PRINT((ACPI_DB_VALUES, "%s.%s = %d\n",
  588                          acpi_name(sc->tz_handle), node, *data));
  589     }
  590 
  591     return_VOID;    
  592 }
  593 
  594 /*
  595  * Sanity-check a temperature value.  Assume that setpoints
  596  * should be between 0C and 150C.
  597  */
  598 static void
  599 acpi_tz_sanity(struct acpi_tz_softc *sc, int *val, char *what)
  600 {
  601     if (*val != -1 && (*val < TZ_ZEROC || *val > TZ_ZEROC + 1500)) {
  602         device_printf(sc->tz_dev, "%s value is absurd, ignored (%d.%dC)\n",
  603                       what, TZ_KELVTOC(*val));
  604         *val = -1;
  605     }
  606 }
  607 
  608 /*
  609  * Respond to a sysctl on the active state node.
  610  */    
  611 static int
  612 acpi_tz_active_sysctl(SYSCTL_HANDLER_ARGS)
  613 {
  614     struct acpi_tz_softc        *sc;
  615     int                         active;
  616     int                         error;
  617 
  618     sc = (struct acpi_tz_softc *)oidp->oid_arg1;
  619     active = sc->tz_active;
  620     error = sysctl_handle_int(oidp, &active, 0, req);
  621 
  622     /* Error or no new value */
  623     if (error != 0 || req->newptr == NULL)
  624         return (error);
  625     if (active < -1 || active >= TZ_NUMLEVELS)
  626         return (EINVAL);
  627 
  628     /* Set new preferred level and re-switch */
  629     sc->tz_requested = active;
  630     acpi_tz_signal(sc, 0);
  631     return (0);
  632 }
  633 
  634 static void
  635 acpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
  636 {
  637     struct acpi_tz_softc        *sc = (struct acpi_tz_softc *)context;
  638 
  639     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  640 
  641     switch (notify) {
  642     case TZ_NOTIFY_TEMPERATURE:
  643         /* Temperature change occurred */
  644         acpi_tz_signal(sc, 0);
  645         break;
  646     case TZ_NOTIFY_DEVICES:
  647     case TZ_NOTIFY_LEVELS:
  648         /* Zone devices/setpoints changed */
  649         acpi_tz_signal(sc, TZ_FLAG_GETSETTINGS);
  650         break;
  651     default:
  652         ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev),
  653                     "unknown Notify event 0x%x\n", notify);
  654         break;
  655     }
  656 
  657     acpi_UserNotify("Thermal", h, notify);
  658 
  659     return_VOID;
  660 }
  661 
  662 static void
  663 acpi_tz_signal(struct acpi_tz_softc *sc, int flags)
  664 {
  665     ACPI_LOCK(thermal);
  666     sc->tz_flags |= flags;
  667     ACPI_UNLOCK(thermal);
  668     wakeup(&acpi_tz_proc);
  669 }
  670 
  671 /*
  672  * Notifies can be generated asynchronously but have also been seen to be
  673  * triggered by other thermal methods.  One system generates a notify of
  674  * 0x81 when the fan is turned on or off.  Another generates it when _SCP
  675  * is called.  To handle these situations, we check the zone via
  676  * acpi_tz_monitor() before evaluating changes to setpoints or the cooling
  677  * policy.
  678  */
  679 static void
  680 acpi_tz_timeout(struct acpi_tz_softc *sc, int flags)
  681 {
  682 
  683     /* Check the current temperature and take action based on it */
  684     acpi_tz_monitor(sc);
  685 
  686     /* If requested, get the power profile settings. */
  687     if (flags & TZ_FLAG_GETPROFILE)
  688         acpi_tz_power_profile(sc);
  689 
  690     /*
  691      * If requested, check for new devices/setpoints.  After finding them,
  692      * check if we need to switch fans based on the new values.
  693      */
  694     if (flags & TZ_FLAG_GETSETTINGS) {
  695         acpi_tz_establish(sc);
  696         acpi_tz_monitor(sc);
  697     }
  698 
  699     /* XXX passive cooling actions? */
  700 }
  701 
  702 /*
  703  * System power profile may have changed; fetch and notify the
  704  * thermal zone accordingly.
  705  *
  706  * Since this can be called from an arbitrary eventhandler, it needs
  707  * to get the ACPI lock itself.
  708  */
  709 static void
  710 acpi_tz_power_profile(void *arg)
  711 {
  712     ACPI_STATUS                 status;
  713     struct acpi_tz_softc        *sc = (struct acpi_tz_softc *)arg;
  714     int                         state;
  715 
  716     state = power_profile_get_state();
  717     if (state != POWER_PROFILE_PERFORMANCE && state != POWER_PROFILE_ECONOMY)
  718         return;
  719 
  720     /* check that we haven't decided there's no _SCP method */
  721     if ((sc->tz_flags & TZ_FLAG_NO_SCP) == 0) {
  722 
  723         /* Call _SCP to set the new profile */
  724         status = acpi_SetInteger(sc->tz_handle, "_SCP", 
  725             (state == POWER_PROFILE_PERFORMANCE) ? 0 : 1);
  726         if (ACPI_FAILURE(status)) {
  727             if (status != AE_NOT_FOUND)
  728                 ACPI_VPRINT(sc->tz_dev,
  729                             acpi_device_get_parent_softc(sc->tz_dev),
  730                             "can't evaluate %s._SCP - %s\n",
  731                             acpi_name(sc->tz_handle),
  732                             AcpiFormatException(status));
  733             sc->tz_flags |= TZ_FLAG_NO_SCP;
  734         } else {
  735             /* We have to re-evaluate the entire zone now */
  736             acpi_tz_signal(sc, TZ_FLAG_GETSETTINGS);
  737         }
  738     }
  739 }
  740 
  741 /*
  742  * Thermal zone monitor thread.
  743  */
  744 static void
  745 acpi_tz_thread(void *arg)
  746 {
  747     device_t    *devs;
  748     int         devcount, i;
  749     int         flags;
  750     struct acpi_tz_softc **sc;
  751 
  752     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  753 
  754     devs = NULL;
  755     devcount = 0;
  756     sc = NULL;
  757 
  758     for (;;) {
  759         /* If the number of devices has changed, re-evaluate. */
  760         if (devclass_get_maxunit(acpi_tz_devclass) != devcount) {
  761             if (devs != NULL) {
  762                 free(devs, M_TEMP);
  763                 free(sc, M_TEMP);
  764             }
  765             devclass_get_devices(acpi_tz_devclass, &devs, &devcount);
  766             sc = malloc(sizeof(struct acpi_tz_softc *) * devcount, M_TEMP,
  767                         M_WAITOK | M_ZERO);
  768             for (i = 0; i < devcount; i++)
  769                 sc[i] = device_get_softc(devs[i]);
  770         }
  771 
  772         /* Check for temperature events and act on them. */
  773         for (i = 0; i < devcount; i++) {
  774             ACPI_LOCK(thermal);
  775             flags = sc[i]->tz_flags;
  776             sc[i]->tz_flags &= TZ_FLAG_NO_SCP;
  777             ACPI_UNLOCK(thermal);
  778             acpi_tz_timeout(sc[i], flags);
  779         }
  780 
  781         /* If more work to do, don't go to sleep yet. */
  782         ACPI_LOCK(thermal);
  783         for (i = 0; i < devcount; i++) {
  784             if (sc[i]->tz_flags & ~TZ_FLAG_NO_SCP)
  785                 break;
  786         }
  787 
  788         /*
  789          * If we have no more work, sleep for a while, setting PDROP so that
  790          * the mutex will not be reacquired.  Otherwise, drop the mutex and
  791          * loop to handle more events.
  792          */
  793         if (i == devcount)
  794             msleep(&acpi_tz_proc, &thermal_mutex, PZERO | PDROP, "tzpoll",
  795                 hz * acpi_tz_polling_rate);
  796         else
  797             ACPI_UNLOCK(thermal);
  798     }
  799 }

Cache object: 7ec85d582f54ecfc837ffcad973fadba


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.