LCOV - code coverage report
Current view: top level - dev/pci - itherm.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 123 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 7 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2010 Mike Larkin <mlarkin@openbsd.org>
       3             :  *
       4             :  * Permission to use, copy, modify, and distribute this software for any
       5             :  * purpose with or without fee is hereby granted, provided that the above
       6             :  * copyright notice and this permission notice appear in all copies.
       7             :  *
       8             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
       9             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      10             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      11             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      12             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      13             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      14             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      15             :  */
      16             : 
      17             : /*
      18             :  * Intel 3400 thermal sensor controller driver
      19             :  */
      20             : 
      21             : #include <sys/param.h>
      22             : #include <sys/systm.h>
      23             : #include <sys/device.h>
      24             : #include <sys/sensors.h>
      25             : 
      26             : #include <dev/pci/pcireg.h>
      27             : #include <dev/pci/pcivar.h>
      28             : #include <dev/pci/pcidevs.h>
      29             : 
      30             : /*
      31             :  * Intel 5 series (3400) Thermal Sensor Data
      32             :  * See Intel document 322169-004 (January 2012)
      33             :  */
      34             : #define ITHERM_NUM_SENSORS              12
      35             : #define ITHERM_SENSOR_THERMOMETER       0
      36             : #define ITHERM_SENSOR_CORETEMP1         1
      37             : #define ITHERM_SENSOR_CORETEMP2         2
      38             : #define ITHERM_SENSOR_COREENERGY        3
      39             : #define ITHERM_SENSOR_GPUTEMP           4
      40             : #define ITHERM_SENSOR_MAXPROCTEMP       5
      41             : #define ITHERM_SENSOR_DIMMTEMP1         6
      42             : #define ITHERM_SENSOR_DIMMTEMP2         7
      43             : #define ITHERM_SENSOR_DIMMTEMP3         8
      44             : #define ITHERM_SENSOR_DIMMTEMP4         9
      45             : #define ITHERM_SENSOR_GPUTEMP_ABSOLUTE  10
      46             : #define ITHERM_SENSOR_PCHTEMP_ABSOLUTE  11
      47             : 
      48             : /* Section 22.2 of datasheet */
      49             : #define ITHERM_TSE      0x1     /* TS enable */
      50             : #define ITHERM_TSTR     0x3     /* TS thermometer read */
      51             : #define ITHERM_TRC      0x1A    /* TS reporting control */
      52             : #define ITHERM_CTV1     0x30    /* TS core temp value 1 */
      53             : #define ITHERM_CTV2     0x32    /* TS core temp value 2 */
      54             : #define ITHERM_CEV1     0x34    /* TS core energy value 1 */
      55             : #define ITHERM_MGTV     0x58    /* mem/GPU temp value */
      56             : #define ITHERM_PTV      0x60    /* TS CPU temp value */
      57             : #define ITHERM_DTV      0xAC    /* DIMM temp values */
      58             : #define ITHERM_ITV      0xD8    /* Internal temp values */
      59             : 
      60             : #define ITHERM_TEMP_READ_ENABLE         0xFF
      61             : #define ITHERM_TDR_ENABLE               0x1000
      62             : #define ITHERM_SECOND_CORE_ENABLE       0x8000
      63             : 
      64             : #define ITHERM_TSE_ENABLE       0xB8    /* magic number in datasheet */
      65             : 
      66             : #define ITHERM_CTV_INVALID      0x8000
      67             : #define ITHERM_CTV_INT_MASK     0x3FC0  /* higher 8 bits */
      68             : #define ITHERM_CTV_FRAC_MASK    0x003F  /* lower 6 bits */
      69             : 
      70             : #define ITHERM_REFRESH_INTERVAL 5
      71             : 
      72             : struct itherm_softc {
      73             :         struct device           sc_dev;
      74             : 
      75             :         bus_addr_t              sc_addr;
      76             :         bus_space_tag_t         iot;
      77             :         bus_space_handle_t      ioh;
      78             :         bus_size_t              size;
      79             : 
      80             :         int64_t                 energy_prev;
      81             : 
      82             :         struct ksensor sensors[ITHERM_NUM_SENSORS];
      83             :         struct ksensordev sensordev;
      84             :         void (*refresh_sensor_data)(struct itherm_softc *);
      85             : };
      86             : 
      87             : #define IREAD1(sc, a) bus_space_read_1((sc)->iot, (sc)->ioh, (a))
      88             : #define IREAD2(sc, a) bus_space_read_2((sc)->iot, (sc)->ioh, (a))
      89             : #define IREAD4(sc, a) bus_space_read_4((sc)->iot, (sc)->ioh, (a))
      90             : #define IWRITE1(sc, a, x) bus_space_write_1((sc)->iot, (sc)->ioh, (a), (x))
      91             : #define IWRITE2(sc, a, x) bus_space_write_2((sc)->iot, (sc)->ioh, (a), (x))
      92             : 
      93             : int  itherm_probe(struct device *, void *, void *);
      94             : void itherm_attach(struct device *, struct device *, void *);
      95             : void itherm_refresh(void *);
      96             : void itherm_enable(struct itherm_softc *);
      97             : void itherm_refresh_sensor_data(struct itherm_softc *);
      98             : int  itherm_activate(struct device *, int);
      99             : void itherm_bias_temperature_sensor(struct ksensor *);
     100             : 
     101             : const struct pci_matchid itherm_devices[] = {
     102             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_3400_THERMAL }
     103             : };
     104             : 
     105             : struct cfdriver itherm_cd = {
     106             :         NULL, "itherm", DV_DULL
     107             : };
     108             : 
     109             : struct cfattach itherm_ca = {
     110             :         sizeof(struct itherm_softc), itherm_probe, itherm_attach, NULL,
     111             :         itherm_activate
     112             : };
     113             : 
     114             : int
     115           0 : itherm_probe(struct device *parent, void *match, void *aux)
     116             : {
     117           0 :         return (pci_matchbyid((struct pci_attach_args *)aux, itherm_devices,
     118             :             sizeof(itherm_devices)/sizeof(itherm_devices[0])));
     119             : }
     120             : 
     121             : void
     122           0 : itherm_attach(struct device *parent, struct device *self, void *aux)
     123             : {
     124           0 :         struct itherm_softc *sc = (struct itherm_softc *)self;
     125           0 :         struct pci_attach_args *pa = aux;
     126             :         int i;
     127             :         pcireg_t v;
     128             : 
     129           0 :         v = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_MAPREG_START);
     130           0 :         v &= PCI_MAPREG_TYPE_MASK | PCI_MAPREG_MEM_TYPE_MASK;
     131           0 :         if (pci_mapreg_map(pa, PCI_MAPREG_START,
     132           0 :             v, 0, &sc->iot, &sc->ioh, NULL, &sc->size, 0)) {
     133           0 :                 printf(": can't map mem space\n");
     134           0 :                 return;
     135             :         }
     136             : 
     137           0 :         sc->sensors[ITHERM_SENSOR_THERMOMETER].type = SENSOR_TEMP;
     138           0 :         sc->sensors[ITHERM_SENSOR_CORETEMP1].type = SENSOR_TEMP;
     139           0 :         sc->sensors[ITHERM_SENSOR_CORETEMP2].type = SENSOR_TEMP;
     140           0 :         sc->sensors[ITHERM_SENSOR_COREENERGY].type = SENSOR_WATTS;
     141           0 :         sc->sensors[ITHERM_SENSOR_GPUTEMP].type = SENSOR_TEMP;
     142           0 :         sc->sensors[ITHERM_SENSOR_MAXPROCTEMP].type = SENSOR_TEMP;
     143           0 :         sc->sensors[ITHERM_SENSOR_DIMMTEMP1].type = SENSOR_TEMP;
     144           0 :         sc->sensors[ITHERM_SENSOR_DIMMTEMP2].type = SENSOR_TEMP;
     145           0 :         sc->sensors[ITHERM_SENSOR_DIMMTEMP3].type = SENSOR_TEMP;
     146           0 :         sc->sensors[ITHERM_SENSOR_DIMMTEMP4].type = SENSOR_TEMP;
     147           0 :         sc->sensors[ITHERM_SENSOR_GPUTEMP_ABSOLUTE].type = SENSOR_TEMP;
     148           0 :         sc->sensors[ITHERM_SENSOR_PCHTEMP_ABSOLUTE].type = SENSOR_TEMP;
     149             : 
     150           0 :         strlcpy(sc->sensors[ITHERM_SENSOR_THERMOMETER].desc,
     151             :             "Thermometer",
     152             :             sizeof(sc->sensors[ITHERM_SENSOR_THERMOMETER].desc));
     153             : 
     154           0 :         strlcpy(sc->sensors[ITHERM_SENSOR_CORETEMP1].desc,
     155             :             "Core 1",
     156             :             sizeof(sc->sensors[ITHERM_SENSOR_CORETEMP1].desc));
     157             : 
     158           0 :         strlcpy(sc->sensors[ITHERM_SENSOR_CORETEMP2].desc,
     159             :             "Core 2",
     160             :             sizeof(sc->sensors[ITHERM_SENSOR_CORETEMP2].desc));
     161             : 
     162           0 :         strlcpy(sc->sensors[ITHERM_SENSOR_COREENERGY].desc,
     163             :             "CPU power consumption",
     164             :             sizeof(sc->sensors[ITHERM_SENSOR_COREENERGY].desc));
     165             : 
     166           0 :         strlcpy(sc->sensors[ITHERM_SENSOR_GPUTEMP].desc,
     167             :             "GPU/Memory Controller Temp",
     168             :             sizeof(sc->sensors[ITHERM_SENSOR_GPUTEMP].desc));
     169             : 
     170           0 :         strlcpy(sc->sensors[ITHERM_SENSOR_MAXPROCTEMP].desc,
     171             :             "CPU/GPU Max temp",
     172             :             sizeof(sc->sensors[ITHERM_SENSOR_MAXPROCTEMP].desc));
     173             : 
     174           0 :         strlcpy(sc->sensors[ITHERM_SENSOR_DIMMTEMP1].desc,
     175             :             "DIMM 1",
     176             :             sizeof(sc->sensors[ITHERM_SENSOR_DIMMTEMP1].desc));
     177             : 
     178           0 :         strlcpy(sc->sensors[ITHERM_SENSOR_DIMMTEMP2].desc,
     179             :             "DIMM 2",
     180             :             sizeof(sc->sensors[ITHERM_SENSOR_DIMMTEMP2].desc));
     181             : 
     182           0 :         strlcpy(sc->sensors[ITHERM_SENSOR_DIMMTEMP3].desc,
     183             :             "DIMM 3",
     184             :             sizeof(sc->sensors[ITHERM_SENSOR_DIMMTEMP3].desc));
     185             : 
     186           0 :         strlcpy(sc->sensors[ITHERM_SENSOR_DIMMTEMP4].desc,
     187             :             "DIMM 4",
     188             :             sizeof(sc->sensors[ITHERM_SENSOR_DIMMTEMP4].desc));
     189             : 
     190           0 :         strlcpy(sc->sensors[ITHERM_SENSOR_GPUTEMP_ABSOLUTE].desc,
     191             :             "GPU/Memory controller abs.",
     192             :             sizeof(sc->sensors[ITHERM_SENSOR_GPUTEMP_ABSOLUTE].desc));
     193             : 
     194           0 :         strlcpy(sc->sensors[ITHERM_SENSOR_PCHTEMP_ABSOLUTE].desc,
     195             :             "PCH abs.",
     196             :             sizeof(sc->sensors[ITHERM_SENSOR_PCHTEMP_ABSOLUTE].desc));
     197             : 
     198           0 :         strlcpy(sc->sensordev.xname, sc->sc_dev.dv_xname,
     199             :             sizeof(sc->sensordev.xname));
     200             : 
     201           0 :         itherm_enable(sc);
     202             : 
     203           0 :         for (i = 0; i < ITHERM_NUM_SENSORS; i++)
     204           0 :                 sensor_attach(&sc->sensordev, &sc->sensors[i]);
     205             : 
     206           0 :         sensordev_install(&sc->sensordev);
     207           0 :         sensor_task_register(sc, itherm_refresh, ITHERM_REFRESH_INTERVAL);
     208             : 
     209           0 :         printf("\n");
     210             : 
     211           0 :         return;
     212           0 : }
     213             : 
     214             : void
     215           0 : itherm_enable(struct itherm_softc *sc)
     216             : {
     217           0 :         sc->energy_prev = 0;
     218             : 
     219             :         /* Enable thermal sensor */
     220           0 :         IWRITE1(sc, ITHERM_TSE, ITHERM_TSE_ENABLE);
     221             : 
     222             :         /* Enable thermal reporting */
     223           0 :         IWRITE2(sc, ITHERM_TRC, (ITHERM_TEMP_READ_ENABLE |
     224             :             ITHERM_TDR_ENABLE | ITHERM_SECOND_CORE_ENABLE));
     225           0 : }
     226             : 
     227             : int
     228           0 : itherm_activate(struct device *self, int act)
     229             : {
     230           0 :         struct itherm_softc *sc = (struct itherm_softc *)self;
     231             : 
     232           0 :         switch (act) {
     233             :         case DVACT_RESUME:
     234           0 :                 itherm_enable(sc);
     235           0 :                 break;
     236             :         }
     237             : 
     238           0 :         return (0);
     239             : }
     240             : 
     241             : void
     242           0 : itherm_refresh_sensor_data(struct itherm_softc *sc)
     243             : {
     244             :         u_int16_t data;
     245             :         int64_t energy;
     246             :         u_int32_t i;
     247             : 
     248             :         /* Thermometer sensor */
     249           0 :         sc->sensors[ITHERM_SENSOR_THERMOMETER].value =
     250           0 :             IREAD1(sc, ITHERM_TSTR);
     251             : 
     252           0 :         itherm_bias_temperature_sensor(
     253             :             &sc->sensors[ITHERM_SENSOR_THERMOMETER]);
     254             : 
     255             :         /*
     256             :          * The Intel 3400 Thermal Sensor has separate sensors for each
     257             :          * core, reported as a 16 bit value. Bits 13:6 are the integer
     258             :          * part of the temperature in C and bits 5:0 are the fractional
     259             :          * part of the temperature, in 1/64 degree C intervals.
     260             :          * Bit 15 is used to indicate an invalid temperature
     261             :          */
     262             : 
     263             :         /* Core 1 temperature */
     264           0 :         data = IREAD2(sc, ITHERM_CTV1);
     265           0 :         if (data & ITHERM_CTV_INVALID)
     266           0 :                 sc->sensors[ITHERM_SENSOR_CORETEMP1].flags |=
     267             :                     SENSOR_FINVALID;
     268             :         else {
     269           0 :                 sc->sensors[ITHERM_SENSOR_CORETEMP1].flags &=
     270             :                     ~SENSOR_FINVALID;
     271           0 :                 sc->sensors[ITHERM_SENSOR_CORETEMP1].value =
     272           0 :                     (data & ITHERM_CTV_INT_MASK) >> 6;
     273           0 :                 sc->sensors[ITHERM_SENSOR_CORETEMP1].value *=
     274             :                     1000000;
     275           0 :                 data &= ITHERM_CTV_FRAC_MASK;
     276           0 :                 data *= 1000000 / 64;
     277           0 :                 sc->sensors[ITHERM_SENSOR_CORETEMP1].value +=
     278           0 :                     data;
     279           0 :                 itherm_bias_temperature_sensor(
     280             :                     &sc->sensors[ITHERM_SENSOR_CORETEMP1]);
     281             :         }
     282             : 
     283             :         /* Core 2 temperature */
     284           0 :         data = IREAD2(sc, ITHERM_CTV2);
     285           0 :         if (data & ITHERM_CTV_INVALID)
     286           0 :                 sc->sensors[ITHERM_SENSOR_CORETEMP2].flags |=
     287             :                     SENSOR_FINVALID;
     288             :         else {
     289           0 :                 sc->sensors[ITHERM_SENSOR_CORETEMP2].flags &=
     290             :                     ~SENSOR_FINVALID;
     291           0 :                 sc->sensors[ITHERM_SENSOR_CORETEMP2].value =
     292           0 :                     (data & ITHERM_CTV_INT_MASK) >> 6;
     293           0 :                 sc->sensors[ITHERM_SENSOR_CORETEMP2].value *=
     294             :                     1000000;
     295           0 :                 data &= ITHERM_CTV_FRAC_MASK;
     296           0 :                 data *= 1000000 / 64;
     297           0 :                 sc->sensors[ITHERM_SENSOR_CORETEMP2].value +=
     298           0 :                     data;
     299           0 :                 itherm_bias_temperature_sensor(
     300             :                     &sc->sensors[ITHERM_SENSOR_CORETEMP2]);
     301             :         }
     302             : 
     303             :         /*
     304             :          * The core energy sensor reports the number of Joules
     305             :          * of energy consumed by the processor since powerup.
     306             :          * This number is scaled by 65535 and is continually
     307             :          * increasing, so we save the old value and compute
     308             :          * the difference for the Watt sensor value.
     309             :          */
     310             : 
     311           0 :         i = IREAD4(sc, ITHERM_CEV1);
     312             :         /* Convert to Joules per interval */
     313           0 :         energy = (i / 65535);
     314           0 :         energy = energy - sc->energy_prev;
     315           0 :         sc->energy_prev = (i / 65535);
     316             :         /* Convert to Joules per second */
     317           0 :         energy = energy / ITHERM_REFRESH_INTERVAL;
     318             :         /* Convert to micro Joules per second (micro Watts) */
     319           0 :         energy = energy * 1000 * 1000;
     320             : 
     321           0 :         sc->sensors[ITHERM_SENSOR_COREENERGY].value = energy;
     322             : 
     323             :         /*
     324             :          * XXX - the GPU temp is reported as a 64 bit value with no
     325             :          * documented structure. Disabled for now
     326             :          */
     327           0 :         sc->sensors[ITHERM_SENSOR_GPUTEMP].flags |= SENSOR_FINVALID;
     328             : #if 0
     329             :         bus_space_read_multi_4(sc->iot, sc->ioh, ITHERM_MGTV,
     330             :             (u_int32_t *)&sc->sensors[ITHERM_SENSOR_GPUTEMP].value, 2);
     331             :         sc->sensors[ITHERM_SENSOR_GPUTEMP].value *= 1000000;
     332             :         sc->sensors[ITHERM_SENSOR_GPUTEMP].value += 273150000;
     333             : #endif
     334             : 
     335             :         /* Max processor temperature */
     336           0 :         sc->sensors[ITHERM_SENSOR_MAXPROCTEMP].value =
     337           0 :             IREAD1(sc, ITHERM_PTV) * 1000000;
     338           0 :         itherm_bias_temperature_sensor(
     339             :             &sc->sensors[ITHERM_SENSOR_MAXPROCTEMP]);
     340             : 
     341             :         /* DIMM 1 */
     342           0 :         sc->sensors[ITHERM_SENSOR_DIMMTEMP1].value =
     343           0 :             IREAD1(sc, ITHERM_DTV) * 1000000;
     344           0 :         itherm_bias_temperature_sensor(
     345             :             &sc->sensors[ITHERM_SENSOR_DIMMTEMP1]);
     346             : 
     347             :         /* DIMM 2 */
     348           0 :         sc->sensors[ITHERM_SENSOR_DIMMTEMP2].value =
     349           0 :             IREAD1(sc, ITHERM_DTV+1) * 1000000;
     350           0 :         itherm_bias_temperature_sensor(
     351             :             &sc->sensors[ITHERM_SENSOR_DIMMTEMP2]);
     352             : 
     353             :         /* DIMM 3 */
     354           0 :         sc->sensors[ITHERM_SENSOR_DIMMTEMP3].value =
     355           0 :             IREAD1(sc, ITHERM_DTV+2) * 1000000;
     356           0 :         itherm_bias_temperature_sensor(
     357             :             &sc->sensors[ITHERM_SENSOR_DIMMTEMP3]);
     358             : 
     359             :         /* DIMM 4 */
     360           0 :         sc->sensors[ITHERM_SENSOR_DIMMTEMP4].value =
     361           0 :             IREAD1(sc, ITHERM_DTV+3) * 1000000;
     362           0 :         itherm_bias_temperature_sensor(
     363             :             &sc->sensors[ITHERM_SENSOR_DIMMTEMP4]);
     364             : 
     365             :         /* GPU Temperature */
     366           0 :         sc->sensors[ITHERM_SENSOR_GPUTEMP_ABSOLUTE].value =
     367           0 :             IREAD1(sc, ITHERM_ITV+1) * 1000000;
     368           0 :         itherm_bias_temperature_sensor(
     369             :             &sc->sensors[ITHERM_SENSOR_GPUTEMP_ABSOLUTE]);
     370             : 
     371             :         /* PCH Temperature */
     372           0 :         sc->sensors[ITHERM_SENSOR_PCHTEMP_ABSOLUTE].value =
     373           0 :             IREAD1(sc, ITHERM_ITV) * 1000000;
     374           0 :         itherm_bias_temperature_sensor(
     375             :             &sc->sensors[ITHERM_SENSOR_PCHTEMP_ABSOLUTE]);
     376           0 : }
     377             : 
     378             : void
     379           0 : itherm_bias_temperature_sensor(struct ksensor *sensor)
     380             : {
     381           0 :         if (sensor->value == 0 || sensor->value == 0xff)
     382           0 :                 sensor->flags |= SENSOR_FINVALID;
     383             :         else
     384           0 :                 sensor->flags &= ~SENSOR_FINVALID;
     385             : 
     386             :         /* Bias anyway from degC to degK, even if invalid */
     387           0 :         sensor->value += 273150000;
     388           0 : }
     389             : 
     390             : void
     391           0 : itherm_refresh(void *arg)
     392             : {
     393           0 :         struct itherm_softc *sc = (struct itherm_softc *)arg;
     394             : 
     395           0 :         itherm_refresh_sensor_data(sc);
     396           0 : }

Generated by: LCOV version 1.13