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/powerpc/powernv/opal_sensor.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) 2018 Justin Hibbits
    3  *
    4  * Redistribution and use in source and binary forms, with or without
    5  * modification, are permitted provided that the following conditions
    6  * are met:
    7  * 1. Redistributions of source code must retain the above copyright
    8  *    notice, this list of conditions and the following disclaimer.
    9  * 2. Redistributions in binary form must reproduce the above copyright
   10  *    notice, this list of conditions and the following disclaimer in the
   11  *    documentation and/or other materials provided with the distribution.
   12  *
   13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   15  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   16  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   17  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   18  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   19  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   20  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   21  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   22  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   23  */
   24 
   25 #include <sys/cdefs.h>
   26 __FBSDID("$FreeBSD$");
   27 
   28 #include <sys/param.h>
   29 #include <sys/kernel.h>
   30 #include <sys/lock.h>
   31 #include <sys/module.h>
   32 #include <sys/mutex.h>
   33 #include <sys/proc.h>
   34 #include <sys/sysctl.h>
   35 #include <sys/systm.h>
   36 #include <sys/endian.h>
   37 
   38 #include <vm/vm.h>
   39 #include <vm/pmap.h>
   40 
   41 #include <machine/bus.h>
   42 
   43 #include <dev/ofw/openfirm.h>
   44 #include <dev/ofw/ofw_bus.h>
   45 #include <dev/ofw/ofw_bus_subr.h>
   46 
   47 #include "opal.h"
   48 
   49 struct opal_sensor_softc {
   50         device_t         sc_dev;
   51         struct mtx       sc_mtx;
   52         uint32_t         sc_handle;
   53         uint32_t         sc_min_handle;
   54         uint32_t         sc_max_handle;
   55         char            *sc_label;
   56         int              sc_type;
   57 };
   58 
   59 #define SENSOR_LOCK(_sc)                mtx_lock(&(_sc)->sc_mtx)
   60 #define SENSOR_UNLOCK(_sc)              mtx_unlock(&(_sc)->sc_mtx)
   61 #define SENSOR_LOCK_INIT(_sc) \
   62         mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \
   63             "opal-sensor", MTX_DEF)
   64 
   65 /*
   66  * A bit confusing, maybe.  There are two types of nodes with compatible strings
   67  * of "ibm,opal-sensor".  One hangs off /ibm,opal/, named "sensors", the other
   68  * hangs off of this node.  For newbus attachments, we have one node (opalsens)
   69  * attach from opal0, and the others (opal_sensor) attach from opalsens.  These
   70  * are the real sensors.
   71  */
   72 enum opal_sensor_type {
   73         OPAL_SENSOR_TEMP        = 0,    /* From OPAL: degC */
   74         OPAL_SENSOR_FAN         = 1,    /* From OPAL: RPM */
   75         OPAL_SENSOR_POWER       = 2,    /* From OPAL: W */
   76         OPAL_SENSOR_IN          = 3,    /* From OPAL: mV */
   77         OPAL_SENSOR_ENERGY      = 4,    /* From OPAL: uJ */
   78         OPAL_SENSOR_CURR        = 5,    /* From OPAL: mA */
   79         OPAL_SENSOR_MAX
   80 };
   81 
   82 /* This must be kept sorted with the enum above. */
   83 const char *opal_sensor_types[] = {
   84         "temp",
   85         "fan",
   86         "power",
   87         "in",
   88         "energy",
   89         "curr"
   90 };
   91 
   92 /*
   93  * Retrieve the raw value from OPAL.  This will be cooked by the sysctl handler.
   94  */
   95 static int
   96 opal_sensor_get_val(struct opal_sensor_softc *sc, uint32_t key, uint64_t *val)
   97 {
   98         struct opal_msg msg;
   99         uint32_t val32;
  100         int rv, token;
  101 
  102         token = opal_alloc_async_token();
  103         SENSOR_LOCK(sc);
  104         rv = opal_call(OPAL_SENSOR_READ, key, token, vtophys(&val32));
  105 
  106         if (rv == OPAL_ASYNC_COMPLETION) {
  107                 /* Sleep a little to let things settle. */
  108                 DELAY(100);
  109                 bzero(&msg, sizeof(msg));
  110                 rv = opal_wait_completion(&msg, sizeof(msg), token);
  111 
  112                 if (rv == OPAL_SUCCESS)
  113                         val32 = msg.params[0];
  114         }
  115         SENSOR_UNLOCK(sc);
  116 
  117         if (rv == OPAL_SUCCESS)
  118                 *val = be32toh(val32);
  119         else
  120                 rv = EIO;
  121 
  122         opal_free_async_token(token);
  123         return (rv);
  124 }
  125 
  126 static int
  127 opal_sensor_sysctl(SYSCTL_HANDLER_ARGS)
  128 {
  129         struct opal_sensor_softc *sc;
  130         int error, result;
  131         uint32_t sensor;
  132         uint64_t sensval;
  133 
  134         sc = arg1;
  135         sensor = arg2;
  136 
  137         error = opal_sensor_get_val(sc, sensor, &sensval);
  138 
  139         if (error)
  140                 return (error);
  141 
  142         result = sensval;
  143 
  144         switch (sc->sc_type) {
  145         case OPAL_SENSOR_TEMP:
  146                 result = result * 10 + 2731; /* Convert to K */
  147                 break;
  148         case OPAL_SENSOR_POWER:
  149                 result = result * 1000; /* Convert to mW */
  150                 break;
  151         }
  152 
  153         error = sysctl_handle_int(oidp, &result, 0, req);
  154 
  155         return (error);
  156 }
  157 
  158 static int
  159 opal_sensor_probe(device_t dev)
  160 {
  161         if (!ofw_bus_is_compatible(dev, "ibm,opal-sensor"))
  162                 return (ENXIO);
  163 
  164         device_set_desc(dev, "OPAL sensor");
  165         return (BUS_PROBE_GENERIC);
  166 }
  167 
  168 static int
  169 opal_sensor_attach(device_t dev)
  170 {
  171         struct opal_sensor_softc *sc;
  172         struct sysctl_ctx_list *ctx;
  173         struct sysctl_oid *tree;
  174         char            type[8];
  175         phandle_t       node;
  176         cell_t          sensor_id;
  177         int             i;
  178 
  179         sc = device_get_softc(dev);
  180         sc->sc_dev = dev;
  181 
  182         node = ofw_bus_get_node(dev);
  183 
  184         if (OF_getencprop(node, "sensor-data", &sensor_id, sizeof(sensor_id)) < 0) {
  185                 device_printf(dev, "Missing sensor ID\n");
  186                 return (ENXIO);
  187         }
  188         if (OF_getprop(node, "sensor-type", type, sizeof(type)) < 0) {
  189                 device_printf(dev, "Missing sensor type\n");
  190                 return (ENXIO);
  191         }
  192 
  193         sc->sc_type = -1;
  194         for (i = 0; i < OPAL_SENSOR_MAX; i++) {
  195                 if (strcmp(type, opal_sensor_types[i]) == 0) {
  196                         sc->sc_type = i;
  197                         break;
  198                 }
  199         }
  200         if (sc->sc_type == -1) {
  201                 device_printf(dev, "Unknown sensor type '%s'\n", type);
  202                 return (ENXIO);
  203         }
  204 
  205         ctx = device_get_sysctl_ctx(dev);
  206         tree = device_get_sysctl_tree(dev);
  207 
  208         sc->sc_handle = sensor_id;
  209         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
  210             "sensor", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc,
  211             sensor_id, opal_sensor_sysctl,
  212             (sc->sc_type == OPAL_SENSOR_TEMP) ? "IK" : "I", "current value");
  213 
  214         SYSCTL_ADD_STRING(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "type",
  215             CTLFLAG_RD, __DECONST(char *, opal_sensor_types[sc->sc_type]),
  216             0, "");
  217 
  218         OF_getprop_alloc(node, "label", (void **)&sc->sc_label);
  219         SYSCTL_ADD_STRING(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "label",
  220             CTLFLAG_RD, sc->sc_label, 0, "");
  221 
  222         if (OF_getencprop(node, "sensor-data-min",
  223             &sensor_id, sizeof(sensor_id)) > 0) {
  224                 sc->sc_min_handle = sensor_id;
  225                 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
  226                     "sensor_min", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
  227                     sc, sensor_id, opal_sensor_sysctl,
  228                     (sc->sc_type == OPAL_SENSOR_TEMP) ? "IK" : "I",
  229                     "minimum value");
  230         }
  231 
  232         if (OF_getencprop(node, "sensor-data-max",
  233             &sensor_id, sizeof(sensor_id)) > 0) {
  234                 sc->sc_max_handle = sensor_id;
  235                 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
  236                     "sensor_max", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
  237                     sc, sensor_id, opal_sensor_sysctl,
  238                     (sc->sc_type == OPAL_SENSOR_TEMP) ? "IK" : "I",
  239                     "maximum value");
  240         }
  241 
  242         SENSOR_LOCK_INIT(sc);
  243 
  244         return (0);
  245 }
  246 
  247 static device_method_t opal_sensor_methods[] = {
  248         DEVMETHOD(device_probe,         opal_sensor_probe),
  249         DEVMETHOD(device_attach,                opal_sensor_attach),
  250 };
  251 
  252 static driver_t opal_sensor_driver = {
  253         "opal_sensor",
  254         opal_sensor_methods,
  255         sizeof(struct opal_sensor_softc)
  256 };
  257 
  258 DRIVER_MODULE(opal_sensor, opalsens, opal_sensor_driver, NULL, NULL);
  259 
  260 static int
  261 opalsens_probe(device_t dev)
  262 {
  263 
  264         if (!ofw_bus_is_compatible(dev, "ibm,opal-sensor"))
  265                 return (ENXIO);
  266 
  267         device_set_desc(dev, "OPAL Sensors");
  268         return (BUS_PROBE_GENERIC);
  269 }
  270 
  271 static int 
  272 opalsens_attach(device_t dev)
  273 {
  274         phandle_t child;
  275         device_t cdev;
  276         struct ofw_bus_devinfo *dinfo;
  277 
  278         for (child = OF_child(ofw_bus_get_node(dev)); child != 0;
  279             child = OF_peer(child)) {
  280                 dinfo = malloc(sizeof(*dinfo), M_DEVBUF, M_WAITOK | M_ZERO);
  281                 if (ofw_bus_gen_setup_devinfo(dinfo, child) != 0) {
  282                         free(dinfo, M_DEVBUF);
  283                         continue;
  284                 }
  285                 cdev = device_add_child(dev, NULL, -1);
  286                 if (cdev == NULL) {
  287                         device_printf(dev, "<%s>: device_add_child failed\n",
  288                             dinfo->obd_name);
  289                         ofw_bus_gen_destroy_devinfo(dinfo);
  290                         free(dinfo, M_DEVBUF);
  291                         continue;
  292                 }
  293                 device_set_ivars(cdev, dinfo);
  294         }
  295 
  296         return (bus_generic_attach(dev));
  297 }
  298 
  299 static const struct ofw_bus_devinfo *
  300 opalsens_get_devinfo(device_t dev, device_t child)
  301 {
  302         return (device_get_ivars(child));
  303 }
  304 
  305 static device_method_t opalsens_methods[] = {
  306         /* Device interface */
  307         DEVMETHOD(device_probe,         opalsens_probe),
  308         DEVMETHOD(device_attach,        opalsens_attach),
  309 
  310         /* ofw_bus interface */
  311         DEVMETHOD(ofw_bus_get_devinfo,  opalsens_get_devinfo),
  312         DEVMETHOD(ofw_bus_get_compat,   ofw_bus_gen_get_compat),
  313         DEVMETHOD(ofw_bus_get_model,    ofw_bus_gen_get_model),
  314         DEVMETHOD(ofw_bus_get_name,     ofw_bus_gen_get_name),
  315         DEVMETHOD(ofw_bus_get_node,     ofw_bus_gen_get_node),
  316         DEVMETHOD(ofw_bus_get_type,     ofw_bus_gen_get_type),
  317 
  318         DEVMETHOD_END
  319 };
  320 
  321 static driver_t opalsens_driver = {
  322         "opalsens",
  323         opalsens_methods,
  324         0
  325 };
  326 
  327 DRIVER_MODULE(opalsens, opal, opalsens_driver, NULL, NULL);

Cache object: 48e6a6e90b9870bcc92fffaaee87a8ed


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