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  *      $FreeBSD: releng/5.0/sys/dev/acpica/acpi_thermal.c 105282 2002-10-16 17:28:53Z jhb $
   28  */
   29 
   30 #include "opt_acpi.h"
   31 #include <sys/param.h>
   32 #include <sys/kernel.h>
   33 #include <sys/kthread.h>
   34 #include <sys/bus.h>
   35 #include <sys/proc.h>
   36 #include <sys/reboot.h>
   37 #include <sys/sysctl.h>
   38 #include <sys/unistd.h>
   39 #include <sys/power.h>
   40 
   41 #include "acpi.h"
   42 
   43 #include <dev/acpica/acpivar.h>
   44 
   45 /*
   46  * Hooks for the ACPI CA debugging infrastructure
   47  */
   48 #define _COMPONENT      ACPI_THERMAL
   49 ACPI_MODULE_NAME("THERMAL")
   50 
   51 #define TZ_ZEROC        2732
   52 #define TZ_KELVTOC(x)   (((x) - TZ_ZEROC) / 10), (((x) - TZ_ZEROC) % 10)
   53 
   54 #define TZ_NOTIFY_TEMPERATURE   0x80
   55 #define TZ_NOTIFY_DEVICES       0x81
   56 #define TZ_NOTIFY_LEVELS        0x82
   57 
   58 #define TZ_POLLRATE     30              /* every 30 seconds by default */
   59 
   60 #define TZ_NUMLEVELS    10              /* defined by ACPI spec */
   61 struct acpi_tz_zone {
   62     int         ac[TZ_NUMLEVELS];
   63     ACPI_BUFFER al[TZ_NUMLEVELS];
   64     int         crt;
   65     int         hot;
   66     ACPI_BUFFER psl;
   67     int         psv;
   68     int         tc1;
   69     int         tc2;
   70     int         tsp;
   71     int         tzp;
   72 };
   73 
   74 
   75 struct acpi_tz_softc {
   76     device_t                    tz_dev;                 /* device handle */
   77     ACPI_HANDLE                 tz_handle;              /* thermal zone handle */
   78     int                         tz_temperature;         /* current temperature */
   79     int                         tz_active;              /* current active cooling */
   80 #define TZ_ACTIVE_NONE          -1
   81     int                         tz_requested;           /* user-requested minimum active cooling */
   82     int                         tz_thflags;             /* current temperature-related flags */
   83 #define TZ_THFLAG_NONE          0
   84 #define TZ_THFLAG_PSV           (1<<0)
   85 #define TZ_THFLAG_HOT           (1<<2)
   86 #define TZ_THFLAG_CRT           (1<<3)    
   87     int                         tz_flags;
   88 #define TZ_FLAG_NO_SCP          (1<<0)                  /* no _SCP method */
   89 #define TZ_FLAG_GETPROFILE      (1<<1)                  /* fetch power_profile in timeout */
   90     struct timespec             tz_cooling_started;     /* current cooling starting time */
   91 
   92     struct sysctl_ctx_list      tz_sysctl_ctx;          /* sysctl tree */
   93     struct sysctl_oid           *tz_sysctl_tree;
   94     
   95     struct acpi_tz_zone         tz_zone;                /* thermal zone parameters */
   96     int                         tz_tmp_updating;
   97 };
   98 
   99 static int      acpi_tz_probe(device_t dev);
  100 static int      acpi_tz_attach(device_t dev);
  101 static int      acpi_tz_establish(struct acpi_tz_softc *sc);
  102 static void     acpi_tz_monitor(struct acpi_tz_softc *sc);
  103 static void     acpi_tz_all_off(struct acpi_tz_softc *sc);
  104 static void     acpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg);
  105 static void     acpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg);
  106 static void     acpi_tz_getparam(struct acpi_tz_softc *sc, char *node, int *data);
  107 static void     acpi_tz_sanity(struct acpi_tz_softc *sc, int *val, char *what);
  108 static int      acpi_tz_active_sysctl(SYSCTL_HANDLER_ARGS);
  109 static void     acpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context);
  110 static void     acpi_tz_timeout(struct acpi_tz_softc *sc);
  111 static void     acpi_tz_power_profile(void *arg);
  112 
  113 static void     acpi_tz_thread(void *arg);
  114 static struct proc *acpi_tz_proc;
  115 
  116 static device_method_t acpi_tz_methods[] = {
  117     /* Device interface */
  118     DEVMETHOD(device_probe,     acpi_tz_probe),
  119     DEVMETHOD(device_attach,    acpi_tz_attach),
  120 
  121     {0, 0}
  122 };
  123 
  124 static driver_t acpi_tz_driver = {
  125     "acpi_tz",
  126     acpi_tz_methods,
  127     sizeof(struct acpi_tz_softc),
  128 };
  129 
  130 static devclass_t acpi_tz_devclass;
  131 DRIVER_MODULE(acpi_tz, acpi, acpi_tz_driver, acpi_tz_devclass, 0, 0);
  132 
  133 static struct sysctl_ctx_list   acpi_tz_sysctl_ctx;
  134 static struct sysctl_oid        *acpi_tz_sysctl_tree;
  135 
  136 static int                      acpi_tz_min_runtime = 0;/* minimum cooling run time */
  137 static int                      acpi_tz_polling_rate = TZ_POLLRATE;
  138 
  139 /*
  140  * Match an ACPI thermal zone.
  141  */
  142 static int
  143 acpi_tz_probe(device_t dev)
  144 {
  145     int         result;
  146     ACPI_LOCK_DECL;
  147     
  148     ACPI_LOCK;
  149     
  150     /* no FUNCTION_TRACE - too noisy */
  151 
  152     if ((acpi_get_type(dev) == ACPI_TYPE_THERMAL) &&
  153         !acpi_disabled("thermal")) {
  154         device_set_desc(dev, "thermal zone");
  155         result = -10;
  156     } else {
  157         result = ENXIO;
  158     }
  159     ACPI_UNLOCK;
  160     return(result);
  161 }
  162 
  163 /*
  164  * Attach to an ACPI thermal zone.
  165  */
  166 static int
  167 acpi_tz_attach(device_t dev)
  168 {
  169     struct acpi_tz_softc        *sc;
  170     struct acpi_softc           *acpi_sc;
  171     int                         error;
  172     char                        oidname[8];
  173     ACPI_LOCK_DECL;
  174 
  175     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  176 
  177     ACPI_LOCK;
  178 
  179     sc = device_get_softc(dev);
  180     sc->tz_dev = dev;
  181     sc->tz_handle = acpi_get_handle(dev);
  182     sc->tz_requested = TZ_ACTIVE_NONE;
  183     sc->tz_tmp_updating = 0;
  184 
  185     /*
  186      * Parse the current state of the thermal zone and build control
  187      * structures.
  188      */
  189     if ((error = acpi_tz_establish(sc)) != 0)
  190         goto out;
  191     
  192     /*
  193      * Register for any Notify events sent to this zone.
  194      */
  195     AcpiInstallNotifyHandler(sc->tz_handle, ACPI_DEVICE_NOTIFY, 
  196                              acpi_tz_notify_handler, sc);
  197 
  198     /*
  199      * Create our sysctl nodes.
  200      *
  201      * XXX we need a mechanism for adding nodes under ACPI.
  202      */
  203     if (device_get_unit(dev) == 0) {
  204         acpi_sc = acpi_device_get_parent_softc(dev);
  205         sysctl_ctx_init(&acpi_tz_sysctl_ctx);
  206         acpi_tz_sysctl_tree = SYSCTL_ADD_NODE(&acpi_tz_sysctl_ctx,
  207                                               SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree),
  208                                               OID_AUTO, "thermal", CTLFLAG_RD, 0, "");
  209         SYSCTL_ADD_INT(&acpi_tz_sysctl_ctx,
  210                        SYSCTL_CHILDREN(acpi_tz_sysctl_tree),
  211                        OID_AUTO, "min_runtime", CTLFLAG_RD | CTLFLAG_RW,
  212                        &acpi_tz_min_runtime, 0, "minimum cooling run time in sec");
  213         SYSCTL_ADD_INT(&acpi_tz_sysctl_ctx,
  214                        SYSCTL_CHILDREN(acpi_tz_sysctl_tree),
  215                        OID_AUTO, "polling_rate", CTLFLAG_RD | CTLFLAG_RW,
  216                        &acpi_tz_polling_rate, 0, "monitor polling rate");
  217     }
  218     sysctl_ctx_init(&sc->tz_sysctl_ctx);
  219     sprintf(oidname, "tz%d", device_get_unit(dev));
  220     sc->tz_sysctl_tree = SYSCTL_ADD_NODE(&sc->tz_sysctl_ctx,
  221                                          SYSCTL_CHILDREN(acpi_tz_sysctl_tree), OID_AUTO,
  222                                          oidname, CTLFLAG_RD, 0, "");
  223     SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
  224                    OID_AUTO, "temperature", CTLFLAG_RD,
  225                    &sc->tz_temperature, 0, "current thermal zone temperature");
  226     SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
  227                     OID_AUTO, "active", CTLTYPE_INT | CTLFLAG_RW,
  228                     sc, 0, acpi_tz_active_sysctl, "I", "");
  229     
  230     SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
  231                    OID_AUTO, "thermal_flags", CTLFLAG_RD,
  232                    &sc->tz_thflags, 0, "thermal zone flags");
  233     SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
  234                    OID_AUTO, "_PSV", CTLFLAG_RD,
  235                    &sc->tz_zone.psv, 0, "");
  236     SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
  237                    OID_AUTO, "_HOT", CTLFLAG_RD,
  238                    &sc->tz_zone.hot, 0, "");
  239     SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
  240                    OID_AUTO, "_CRT", CTLFLAG_RD,
  241                    &sc->tz_zone.crt, 0, "");
  242     SYSCTL_ADD_OPAQUE(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
  243                       OID_AUTO, "_ACx", CTLFLAG_RD, &sc->tz_zone.ac,
  244                       sizeof(sc->tz_zone.ac), "I", "");
  245 
  246 
  247     /*
  248      * Register our power profile event handler, and flag it for a manual
  249      * invocation by our timeout.  We defer it like this so that the rest
  250      * of the subsystem has time to come up.
  251      */
  252     EVENTHANDLER_REGISTER(power_profile_change, acpi_tz_power_profile, sc, 0);
  253     sc->tz_flags |= TZ_FLAG_GETPROFILE;
  254 
  255     /*
  256      * Don't bother evaluating/printing the temperature at this point;
  257      * on many systems it'll be bogus until the EC is running.
  258      */
  259 
  260     /*
  261      * Create our thread; we only need one, it will service all of the
  262      * thermal zones.
  263      */
  264     if (acpi_tz_proc == NULL) {
  265             error = kthread_create(acpi_tz_thread, NULL, &acpi_tz_proc,
  266                                    RFHIGHPID, 0, "acpi_thermal");
  267             if (error != 0) {
  268                     device_printf(sc->tz_dev, "could not create thread - %d", error);
  269                     goto out;
  270             }
  271     }
  272         
  273  out:
  274     ACPI_UNLOCK;
  275 
  276     return_VALUE(error);
  277 }
  278 
  279 /*
  280  * Parse the current state of this thermal zone and set up to use it.
  281  *
  282  * Note that we may have previous state, which will have to be discarded.
  283  */
  284 static int
  285 acpi_tz_establish(struct acpi_tz_softc *sc)
  286 {
  287     ACPI_OBJECT *obj;
  288     int         i;
  289     char        nbuf[8];
  290     
  291     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  292 
  293     ACPI_ASSERTLOCK;
  294 
  295     /*
  296      * Power everything off and erase any existing state.
  297      */
  298     acpi_tz_all_off(sc);
  299     for (i = 0; i < TZ_NUMLEVELS; i++)
  300         if (sc->tz_zone.al[i].Pointer != NULL)
  301             AcpiOsFree(sc->tz_zone.al[i].Pointer);
  302     if (sc->tz_zone.psl.Pointer != NULL)
  303         AcpiOsFree(sc->tz_zone.psl.Pointer);
  304     bzero(&sc->tz_zone, sizeof(sc->tz_zone));
  305 
  306     /*
  307      * Evaluate thermal zone parameters.
  308      */
  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 object 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     /*
  350      * Power off everything that we've just been given.
  351      */
  352     acpi_tz_all_off(sc);
  353 
  354     return_VALUE(0);
  355 }
  356 
  357 static char     *aclevel_string[] =     {
  358         "NONE", "_AC0", "_AC1", "_AC2", "_AC3", "_AC4",
  359         "_AC5", "_AC6", "_AC7", "_AC8", "_AC9" };
  360 
  361 static __inline const char *
  362 acpi_tz_aclevel_string(int active)
  363 {
  364         if (active < -1 || active >= TZ_NUMLEVELS) {
  365                 return (aclevel_string[0]);
  366         }
  367 
  368         return (aclevel_string[active+1]);
  369 }
  370 
  371 /*
  372  * Evaluate the condition of a thermal zone, take appropriate actions.
  373  */
  374 static void
  375 acpi_tz_monitor(struct acpi_tz_softc *sc)
  376 {
  377     int         temp;
  378     int         i;
  379     int         newactive, newflags;
  380     struct      timespec curtime;
  381     ACPI_STATUS status;
  382 
  383     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  384 
  385     ACPI_ASSERTLOCK;
  386 
  387     if (sc->tz_tmp_updating) {
  388         goto out;
  389     }
  390     sc->tz_tmp_updating = 1;
  391 
  392     /*
  393      * Get the current temperature.
  394      */
  395     if (ACPI_FAILURE(status = acpi_EvaluateInteger(sc->tz_handle, "_TMP", &temp))) {
  396         ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev),
  397             "error fetching current temperature -- %s\n",
  398              AcpiFormatException(status));
  399         /* XXX disable zone? go to max cooling? */
  400         goto out;
  401     }
  402 
  403     ACPI_DEBUG_PRINT((ACPI_DB_VALUES, "got %d.%dC\n", TZ_KELVTOC(temp)));
  404     sc->tz_temperature = temp;
  405 
  406     /*
  407      * Work out what we ought to be doing right now.
  408      *
  409      * Note that the _ACx levels sort from hot to cold.
  410      */
  411     newactive = TZ_ACTIVE_NONE;
  412     for (i = TZ_NUMLEVELS - 1; i >= 0; i--) {
  413         if ((sc->tz_zone.ac[i] != -1) && (temp >= sc->tz_zone.ac[i])) {
  414             newactive = i;
  415             if (sc->tz_active != newactive) {
  416                 ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev),
  417                     "_AC%d: temperature %d.%d >= setpoint %d.%d\n", i,
  418                     TZ_KELVTOC(temp), TZ_KELVTOC(sc->tz_zone.ac[i]));
  419                 getnanotime(&sc->tz_cooling_started);
  420             }
  421         }
  422     }
  423 
  424     /*
  425      * We are going to get _ACx level down (colder side), but give a guaranteed
  426      * minimum cooling run time if requested.
  427      */
  428     if (acpi_tz_min_runtime > 0 && sc->tz_active != TZ_ACTIVE_NONE &&
  429         (newactive == TZ_ACTIVE_NONE || newactive > sc->tz_active)) {
  430         getnanotime(&curtime);
  431         timespecsub(&curtime, &sc->tz_cooling_started);
  432         if (curtime.tv_sec < acpi_tz_min_runtime) {
  433             newactive = sc->tz_active;
  434         }
  435     }
  436 
  437     /* handle user override of active mode */
  438     if (sc->tz_requested > newactive)
  439         newactive = sc->tz_requested;
  440 
  441     /* update temperature-related flags */
  442     newflags = TZ_THFLAG_NONE;
  443     if ((sc->tz_zone.psv != -1) && (temp >= sc->tz_zone.psv))
  444         newflags |= TZ_THFLAG_PSV;
  445     if ((sc->tz_zone.hot != -1) && (temp >= sc->tz_zone.hot))
  446         newflags |= TZ_THFLAG_HOT;
  447     if ((sc->tz_zone.crt != -1) && (temp >= sc->tz_zone.crt))
  448         newflags |= TZ_THFLAG_CRT;
  449 
  450     /*
  451      * If the active cooling state has changed, we have to switch things.
  452      */
  453     if (newactive != sc->tz_active) {
  454 
  455         /* turn off the cooling devices that are on, if any are */
  456         if (sc->tz_active != TZ_ACTIVE_NONE)
  457             acpi_ForeachPackageObject((ACPI_OBJECT *)sc->tz_zone.al[sc->tz_active].Pointer,
  458                                       acpi_tz_switch_cooler_off, sc);
  459 
  460         /* turn on cooling devices that are required, if any are */
  461         if (newactive != TZ_ACTIVE_NONE)
  462             acpi_ForeachPackageObject((ACPI_OBJECT *)sc->tz_zone.al[newactive].Pointer,
  463                                       acpi_tz_switch_cooler_on, sc);
  464         ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev),
  465             "switched from %s to %s: %d.%dC\n",
  466             acpi_tz_aclevel_string(sc->tz_active),
  467             acpi_tz_aclevel_string(newactive), TZ_KELVTOC(temp));
  468         sc->tz_active = newactive;
  469     }
  470 
  471     /*
  472      * XXX (de)activate any passive cooling that may be required.
  473      */
  474 
  475     /*
  476      * If we have just become _HOT or _CRT, warn the user.
  477      *
  478      * We should actually shut down at this point, but it's not clear
  479      * that some systems don't actually map _CRT to the same value as _AC0.
  480      */
  481     if ((newflags & (TZ_THFLAG_HOT | TZ_THFLAG_CRT)) && 
  482         !(sc->tz_thflags & (TZ_THFLAG_HOT | TZ_THFLAG_CRT))) {
  483         device_printf(sc->tz_dev, "WARNING - current temperature (%d.%dC) exceeds system limits\n",
  484                       TZ_KELVTOC(sc->tz_temperature));
  485         /* shutdown_nice(RB_POWEROFF);*/
  486     }
  487     sc->tz_thflags = newflags;
  488 
  489 out:
  490     sc->tz_tmp_updating = 0;
  491     return_VOID;
  492 }
  493 
  494 /*
  495  * Turn off all the cooling devices.
  496  */
  497 static void
  498 acpi_tz_all_off(struct acpi_tz_softc *sc)
  499 {
  500     int         i;
  501 
  502     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  503 
  504     ACPI_ASSERTLOCK;
  505     
  506     /*
  507      * Scan all the _ALx objects, and turn them all off.
  508      */
  509     for (i = 0; i < TZ_NUMLEVELS; i++) {
  510         if (sc->tz_zone.al[i].Pointer == NULL)
  511             continue;
  512         acpi_ForeachPackageObject((ACPI_OBJECT *)sc->tz_zone.al[i].Pointer,
  513                                   acpi_tz_switch_cooler_off, sc);
  514     }
  515 
  516     /*
  517      * XXX revert any passive-cooling options.
  518      */
  519 
  520     sc->tz_active = TZ_ACTIVE_NONE;
  521     sc->tz_thflags = TZ_THFLAG_NONE;
  522     return_VOID;
  523 }
  524 
  525 /*
  526  * Given an object, verify that it's a reference to a device of some sort, 
  527  * and try to switch it off.
  528  */
  529 static void
  530 acpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg)
  531 {
  532     ACPI_HANDLE         cooler;
  533 
  534     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  535 
  536     ACPI_ASSERTLOCK;
  537 
  538     switch(obj->Type) {
  539     case ACPI_TYPE_ANY:
  540         ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s off\n", acpi_name(obj->Reference.Handle)));
  541 
  542         acpi_pwr_switch_consumer(obj->Reference.Handle, ACPI_STATE_D3);
  543         break;
  544         
  545     case ACPI_TYPE_STRING:
  546         ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s off\n", obj->String.Pointer));
  547 
  548         /*
  549          * Find the handle for the device and turn it off.
  550          * The String object here seems to contain a fully-qualified path, so we
  551          * don't have to search for it in our parents.
  552          *
  553          * XXX This may not always be the case.
  554          */
  555         if (ACPI_SUCCESS(AcpiGetHandle(NULL, obj->String.Pointer, &cooler)))
  556             acpi_pwr_switch_consumer(cooler, ACPI_STATE_D3);
  557         break;
  558         
  559     default:
  560         ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to handle unsupported object type %d\n",
  561                           obj->Type));
  562         break;
  563     }
  564     return_VOID;
  565 }
  566 
  567 /*
  568  * Given an object, verify that it's a reference to a device of some sort, 
  569  * and try to switch it on.
  570  *
  571  * XXX replication of off/on function code is bad, mmmkay?
  572  */
  573 static void
  574 acpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg)
  575 {
  576     struct acpi_tz_softc        *sc = (struct acpi_tz_softc *)arg;
  577     ACPI_HANDLE                 cooler;
  578     ACPI_STATUS                 status;
  579     
  580     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  581 
  582     ACPI_ASSERTLOCK;
  583 
  584     switch(obj->Type) {
  585     case ACPI_TYPE_ANY:
  586         ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s on\n", acpi_name(obj->Reference.Handle)));
  587 
  588         if (ACPI_FAILURE(status = acpi_pwr_switch_consumer(obj->Reference.Handle, ACPI_STATE_D0))) {
  589             ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev),
  590                 "failed to activate %s - %s\n", acpi_name(obj->Reference.Handle),
  591                 AcpiFormatException(status));
  592         }
  593         break;
  594         
  595     case ACPI_TYPE_STRING:
  596         ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s on\n", obj->String.Pointer));
  597 
  598         /*
  599          * Find the handle for the device and turn it off.
  600          * The String object here seems to contain a fully-qualified path, so we
  601          * don't have to search for it in our parents.
  602          *
  603          * XXX This may not always be the case.
  604          */
  605         if (ACPI_SUCCESS(AcpiGetHandle(NULL, obj->String.Pointer, &cooler))) {
  606             if (ACPI_FAILURE(status = acpi_pwr_switch_consumer(cooler, ACPI_STATE_D0))) {
  607                 ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev),
  608                     "failed to activate %s - %s\n",
  609                     obj->String.Pointer, AcpiFormatException(status));
  610             }
  611         } else {
  612             ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev),
  613                 "couldn't find %s\n", obj->String.Pointer);
  614         }
  615         break;
  616         
  617     default:
  618         ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to handle unsupported object type %d\n",
  619                           obj->Type));
  620         break;
  621     }
  622         return_VOID;
  623 }
  624 
  625 /*
  626  * Read/debug-print a parameter, default it to -1.
  627  */
  628 static void
  629 acpi_tz_getparam(struct acpi_tz_softc *sc, char *node, int *data)
  630 {
  631 
  632     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  633 
  634     ACPI_ASSERTLOCK;
  635 
  636     if (ACPI_FAILURE(acpi_EvaluateInteger(sc->tz_handle, node, data))) {
  637         *data = -1;
  638     } else {
  639         ACPI_DEBUG_PRINT((ACPI_DB_VALUES, "%s.%s = %d\n", acpi_name(sc->tz_handle),
  640                           node, *data));
  641     }
  642     return_VOID;    
  643 }
  644 
  645 /*
  646  * Sanity-check a temperature value.  Assume that setpoints
  647  * should be between 0C and 150C.
  648  */
  649 static void
  650 acpi_tz_sanity(struct acpi_tz_softc *sc, int *val, char *what)
  651 {
  652     if ((*val != -1) && ((*val < TZ_ZEROC) || (*val > (TZ_ZEROC + 1500)))) {
  653         device_printf(sc->tz_dev, "%s value is absurd, ignored (%d.%dC)\n",
  654                       what, TZ_KELVTOC(*val));
  655         *val = -1;
  656     }
  657 }
  658 
  659 /*
  660  * Respond to a sysctl on the active state node.
  661  */    
  662 static int
  663 acpi_tz_active_sysctl(SYSCTL_HANDLER_ARGS)
  664 {
  665     struct acpi_tz_softc        *sc;
  666     int                         active;
  667     int                         error;
  668     ACPI_LOCK_DECL;
  669 
  670     ACPI_LOCK;
  671 
  672     sc = (struct acpi_tz_softc *)oidp->oid_arg1;
  673     active = sc->tz_active;
  674     error = sysctl_handle_int(oidp, &active, 0, req);
  675 
  676     /* error or no new value */
  677     if ((error != 0) || (req->newptr == NULL))
  678         goto out;
  679     
  680     /* range check */
  681     if ((active < -1) || (active >= TZ_NUMLEVELS)) {
  682         error = EINVAL;
  683         goto out;
  684     }
  685 
  686     /* set new preferred level and re-switch */
  687     sc->tz_requested = active;
  688     acpi_tz_monitor(sc);
  689 
  690  out:
  691     ACPI_UNLOCK;
  692     return(error);
  693 }
  694 
  695 /*
  696  * Respond to a Notify event sent to the zone.
  697  */
  698 static void
  699 acpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
  700 {
  701     struct acpi_tz_softc        *sc = (struct acpi_tz_softc *)context;
  702 
  703     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  704 
  705     ACPI_ASSERTLOCK;
  706 
  707     switch(notify) {
  708     case TZ_NOTIFY_TEMPERATURE:
  709         /* temperature change occurred */
  710         AcpiOsQueueForExecution(OSD_PRIORITY_HIGH, (OSD_EXECUTION_CALLBACK)acpi_tz_monitor, sc);
  711         break;
  712     case TZ_NOTIFY_DEVICES:
  713     case TZ_NOTIFY_LEVELS:
  714         /* zone devices/setpoints changed */
  715         AcpiOsQueueForExecution(OSD_PRIORITY_HIGH, (OSD_EXECUTION_CALLBACK)acpi_tz_establish, sc);
  716         break;
  717     default:
  718         ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev),
  719             "unknown Notify event 0x%x\n", notify);
  720         break;
  721     }
  722     return_VOID;
  723 }
  724 
  725 /*
  726  * Poll the thermal zone.
  727  */
  728 static void
  729 acpi_tz_timeout(struct acpi_tz_softc *sc)
  730 {
  731 
  732     /* do we need to get the power profile settings? */
  733     if (sc->tz_flags & TZ_FLAG_GETPROFILE) {
  734         acpi_tz_power_profile((void *)sc);
  735         sc->tz_flags &= ~TZ_FLAG_GETPROFILE;
  736     }
  737 
  738     ACPI_ASSERTLOCK;
  739 
  740     /* check the current temperature and take action based on it */
  741     acpi_tz_monitor(sc);
  742 
  743     /* XXX passive cooling actions? */
  744 }
  745 
  746 /*
  747  * System power profile may have changed; fetch and notify the
  748  * thermal zone accordingly.
  749  *
  750  * Since this can be called from an arbitrary eventhandler, it needs
  751  * to get the ACPI lock itself.
  752  */
  753 static void
  754 acpi_tz_power_profile(void *arg)
  755 {
  756     ACPI_OBJECT_LIST            args;
  757     ACPI_OBJECT                 obj;
  758     ACPI_STATUS                 status;
  759     struct acpi_tz_softc        *sc = (struct acpi_tz_softc *)arg;
  760     int                         state;
  761     ACPI_LOCK_DECL;
  762 
  763     state = power_profile_get_state();
  764     if (state != POWER_PROFILE_PERFORMANCE &&
  765         state != POWER_PROFILE_ECONOMY) {
  766         return;
  767     }
  768 
  769     ACPI_LOCK;
  770 
  771     /* check that we haven't decided there's no _SCP method */
  772     if (!(sc->tz_flags & TZ_FLAG_NO_SCP)) {
  773 
  774         /* call _SCP to set the new profile */
  775         obj.Type = ACPI_TYPE_INTEGER;
  776         obj.Integer.Value = (state == POWER_PROFILE_PERFORMANCE) ? 0 : 1;
  777         args.Count = 1;
  778         args.Pointer = &obj;
  779         if (ACPI_FAILURE(status = AcpiEvaluateObject(sc->tz_handle, "_SCP", &args, NULL))) {
  780             if (status != AE_NOT_FOUND)
  781                 ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev),
  782                     "can't evaluate %s._SCP - %s\n", acpi_name(sc->tz_handle),
  783                     AcpiFormatException(status));
  784             sc->tz_flags |= TZ_FLAG_NO_SCP;
  785         } else {
  786             /* we have to re-evaluate the entire zone now */
  787             AcpiOsQueueForExecution(OSD_PRIORITY_HIGH, (OSD_EXECUTION_CALLBACK)acpi_tz_establish, sc);
  788         }
  789     }
  790     ACPI_UNLOCK;
  791 }
  792 
  793 /*
  794  * Thermal zone monitor thread.
  795  */
  796 static void
  797 acpi_tz_thread(void *arg)
  798 {
  799     device_t    *devs;
  800     int         devcount, i;
  801     ACPI_LOCK_DECL;
  802 
  803     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  804 
  805 
  806     devs = NULL;
  807     devcount = 0;
  808 
  809     for (;;) {
  810         tsleep(&acpi_tz_proc, PZERO, "nothing", hz * acpi_tz_polling_rate);
  811 
  812 #if __FreeBSD_version >= 500000
  813         mtx_lock(&Giant);
  814 #endif
  815 
  816         if (devcount == 0)
  817             devclass_get_devices(acpi_tz_devclass, &devs, &devcount);
  818 
  819         ACPI_LOCK;
  820         for (i = 0; i < devcount; i++)
  821             acpi_tz_timeout(device_get_softc(devs[i]));
  822         ACPI_UNLOCK;
  823 
  824 #if __FreeBSD_version >= 500000
  825         mtx_unlock(&Giant);
  826 #endif
  827     }
  828 }

Cache object: ca003d95d36420e5d2ace8d22618e19e


[ 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.