1*7698c759SSepherosa Ziehau /* 2*7698c759SSepherosa Ziehau * Copyright (c) 2015 The DragonFly Project. All rights reserved. 3*7698c759SSepherosa Ziehau * 4*7698c759SSepherosa Ziehau * This code is derived from software contributed to The DragonFly Project 5*7698c759SSepherosa Ziehau * by Sepherosa Ziehau <sepherosa@gmail.com> 6*7698c759SSepherosa Ziehau * 7*7698c759SSepherosa Ziehau * Redistribution and use in source and binary forms, with or without 8*7698c759SSepherosa Ziehau * modification, are permitted provided that the following conditions 9*7698c759SSepherosa Ziehau * are met: 10*7698c759SSepherosa Ziehau * 11*7698c759SSepherosa Ziehau * 1. Redistributions of source code must retain the above copyright 12*7698c759SSepherosa Ziehau * notice, this list of conditions and the following disclaimer. 13*7698c759SSepherosa Ziehau * 2. Redistributions in binary form must reproduce the above copyright 14*7698c759SSepherosa Ziehau * notice, this list of conditions and the following disclaimer in 15*7698c759SSepherosa Ziehau * the documentation and/or other materials provided with the 16*7698c759SSepherosa Ziehau * distribution. 17*7698c759SSepherosa Ziehau * 3. Neither the name of The DragonFly Project nor the names of its 18*7698c759SSepherosa Ziehau * contributors may be used to endorse or promote products derived 19*7698c759SSepherosa Ziehau * from this software without specific, prior written permission. 20*7698c759SSepherosa Ziehau * 21*7698c759SSepherosa Ziehau * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22*7698c759SSepherosa Ziehau * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23*7698c759SSepherosa Ziehau * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24*7698c759SSepherosa Ziehau * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25*7698c759SSepherosa Ziehau * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26*7698c759SSepherosa Ziehau * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27*7698c759SSepherosa Ziehau * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28*7698c759SSepherosa Ziehau * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29*7698c759SSepherosa Ziehau * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30*7698c759SSepherosa Ziehau * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31*7698c759SSepherosa Ziehau * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32*7698c759SSepherosa Ziehau * SUCH DAMAGE. 33*7698c759SSepherosa Ziehau */ 34*7698c759SSepherosa Ziehau 35*7698c759SSepherosa Ziehau #include <sys/param.h> 36*7698c759SSepherosa Ziehau #include <sys/systm.h> 37*7698c759SSepherosa Ziehau #include <sys/bitops.h> 38*7698c759SSepherosa Ziehau #include <sys/bus.h> 39*7698c759SSepherosa Ziehau #include <sys/kernel.h> 40*7698c759SSepherosa Ziehau #include <sys/malloc.h> 41*7698c759SSepherosa Ziehau #include <sys/sensors.h> 42*7698c759SSepherosa Ziehau #include <sys/sysctl.h> 43*7698c759SSepherosa Ziehau 44*7698c759SSepherosa Ziehau #include <bus/pci/pcivar.h> 45*7698c759SSepherosa Ziehau #include <bus/pci/pcireg.h> 46*7698c759SSepherosa Ziehau #include <bus/pci/pcibus.h> 47*7698c759SSepherosa Ziehau #include <bus/pci/pci_cfgreg.h> 48*7698c759SSepherosa Ziehau #include <bus/pci/pcib_private.h> 49*7698c759SSepherosa Ziehau 50*7698c759SSepherosa Ziehau #include "pcib_if.h" 51*7698c759SSepherosa Ziehau 52*7698c759SSepherosa Ziehau #include <dev/misc/ecc/ecc_e5_reg.h> 53*7698c759SSepherosa Ziehau 54*7698c759SSepherosa Ziehau #define UBOX_READ(dev, ofs, w) \ 55*7698c759SSepherosa Ziehau pcib_read_config((dev), pci_get_bus((dev)), \ 56*7698c759SSepherosa Ziehau PCISLOT_E5_UBOX0, PCIFUNC_E5_UBOX0, (ofs), w) 57*7698c759SSepherosa Ziehau #define UBOX_READ_2(dev, ofs) UBOX_READ((dev), (ofs), 2) 58*7698c759SSepherosa Ziehau #define UBOX_READ_4(dev, ofs) UBOX_READ((dev), (ofs), 4) 59*7698c759SSepherosa Ziehau 60*7698c759SSepherosa Ziehau #define IMC_CPGC_READ(dev, ofs, w) \ 61*7698c759SSepherosa Ziehau pcib_read_config((dev), pci_get_bus((dev)), \ 62*7698c759SSepherosa Ziehau PCISLOT_E5_IMC_CPGC, PCIFUNC_E5_IMC_CPGC, (ofs), w) 63*7698c759SSepherosa Ziehau #define IMC_CPGC_READ_2(dev, ofs) IMC_CPGC_READ((dev), (ofs), 2) 64*7698c759SSepherosa Ziehau #define IMC_CPGC_READ_4(dev, ofs) IMC_CPGC_READ((dev), (ofs), 4) 65*7698c759SSepherosa Ziehau 66*7698c759SSepherosa Ziehau #define IMC_CTAD_READ(dev, c, ofs, w) \ 67*7698c759SSepherosa Ziehau pcib_read_config((dev), pci_get_bus((dev)), \ 68*7698c759SSepherosa Ziehau PCISLOT_E5_IMC_CTAD, PCIFUNC_E5_IMC_CTAD((c)), (ofs), w) 69*7698c759SSepherosa Ziehau #define IMC_CTAD_READ_2(dev, c, ofs) IMC_CTAD_READ((dev), (c), (ofs), 2) 70*7698c759SSepherosa Ziehau #define IMC_CTAD_READ_4(dev, c, ofs) IMC_CTAD_READ((dev), (c), (ofs), 4) 71*7698c759SSepherosa Ziehau 72*7698c759SSepherosa Ziehau struct memtemp_e5_type { 73*7698c759SSepherosa Ziehau uint16_t did; 74*7698c759SSepherosa Ziehau int slot; 75*7698c759SSepherosa Ziehau int func; 76*7698c759SSepherosa Ziehau int chan; 77*7698c759SSepherosa Ziehau const char *desc; 78*7698c759SSepherosa Ziehau }; 79*7698c759SSepherosa Ziehau 80*7698c759SSepherosa Ziehau struct memtemp_e5_softc; 81*7698c759SSepherosa Ziehau 82*7698c759SSepherosa Ziehau struct memtemp_e5_dimm { 83*7698c759SSepherosa Ziehau TAILQ_ENTRY(memtemp_e5_dimm) dimm_link; 84*7698c759SSepherosa Ziehau struct ksensordev dimm_sensordev; 85*7698c759SSepherosa Ziehau struct ksensor dimm_sensor; 86*7698c759SSepherosa Ziehau struct memtemp_e5_softc *dimm_parent; 87*7698c759SSepherosa Ziehau int dimm_id; 88*7698c759SSepherosa Ziehau int dimm_extid; 89*7698c759SSepherosa Ziehau }; 90*7698c759SSepherosa Ziehau 91*7698c759SSepherosa Ziehau struct memtemp_e5_softc { 92*7698c759SSepherosa Ziehau device_t temp_dev; 93*7698c759SSepherosa Ziehau int temp_chan; 94*7698c759SSepherosa Ziehau int temp_node; 95*7698c759SSepherosa Ziehau TAILQ_HEAD(, memtemp_e5_dimm) temp_dimm; 96*7698c759SSepherosa Ziehau }; 97*7698c759SSepherosa Ziehau 98*7698c759SSepherosa Ziehau static int memtemp_e5_probe(device_t); 99*7698c759SSepherosa Ziehau static int memtemp_e5_attach(device_t); 100*7698c759SSepherosa Ziehau static int memtemp_e5_detach(device_t); 101*7698c759SSepherosa Ziehau 102*7698c759SSepherosa Ziehau static void memtemp_e5_sensor_task(void *); 103*7698c759SSepherosa Ziehau 104*7698c759SSepherosa Ziehau #define MEMTEMP_E5_TYPE_V2(c) \ 105*7698c759SSepherosa Ziehau { \ 106*7698c759SSepherosa Ziehau .did = PCI_E5_IMC_THERMAL_CHN##c##_DID_ID, \ 107*7698c759SSepherosa Ziehau .slot = PCISLOT_E5_IMC_THERMAL, \ 108*7698c759SSepherosa Ziehau .func = PCIFUNC_E5_IMC_THERMAL_CHN##c, \ 109*7698c759SSepherosa Ziehau .chan = c, \ 110*7698c759SSepherosa Ziehau .desc = "Intel E5 v2 memory thermal sensor" \ 111*7698c759SSepherosa Ziehau } 112*7698c759SSepherosa Ziehau 113*7698c759SSepherosa Ziehau #define MEMTEMP_E5_TYPE_END { 0, 0, 0, 0, NULL } 114*7698c759SSepherosa Ziehau 115*7698c759SSepherosa Ziehau static const struct memtemp_e5_type memtemp_types[] = { 116*7698c759SSepherosa Ziehau MEMTEMP_E5_TYPE_V2(0), 117*7698c759SSepherosa Ziehau MEMTEMP_E5_TYPE_V2(1), 118*7698c759SSepherosa Ziehau MEMTEMP_E5_TYPE_V2(2), 119*7698c759SSepherosa Ziehau MEMTEMP_E5_TYPE_V2(3), 120*7698c759SSepherosa Ziehau 121*7698c759SSepherosa Ziehau MEMTEMP_E5_TYPE_END 122*7698c759SSepherosa Ziehau }; 123*7698c759SSepherosa Ziehau 124*7698c759SSepherosa Ziehau #undef MEMTEMP_E5_TYPE_V2 125*7698c759SSepherosa Ziehau #undef MEMTEMP_E5_TYPE_END 126*7698c759SSepherosa Ziehau 127*7698c759SSepherosa Ziehau static device_method_t memtemp_e5_methods[] = { 128*7698c759SSepherosa Ziehau /* Device interface */ 129*7698c759SSepherosa Ziehau DEVMETHOD(device_probe, memtemp_e5_probe), 130*7698c759SSepherosa Ziehau DEVMETHOD(device_attach, memtemp_e5_attach), 131*7698c759SSepherosa Ziehau DEVMETHOD(device_detach, memtemp_e5_detach), 132*7698c759SSepherosa Ziehau DEVMETHOD(device_shutdown, bus_generic_shutdown), 133*7698c759SSepherosa Ziehau DEVMETHOD(device_suspend, bus_generic_suspend), 134*7698c759SSepherosa Ziehau DEVMETHOD(device_resume, bus_generic_resume), 135*7698c759SSepherosa Ziehau DEVMETHOD_END 136*7698c759SSepherosa Ziehau }; 137*7698c759SSepherosa Ziehau 138*7698c759SSepherosa Ziehau static driver_t memtemp_e5_driver = { 139*7698c759SSepherosa Ziehau "memtemp", 140*7698c759SSepherosa Ziehau memtemp_e5_methods, 141*7698c759SSepherosa Ziehau sizeof(struct memtemp_e5_softc) 142*7698c759SSepherosa Ziehau }; 143*7698c759SSepherosa Ziehau static devclass_t memtemp_devclass; 144*7698c759SSepherosa Ziehau DRIVER_MODULE(memtemp_e5, pci, memtemp_e5_driver, memtemp_devclass, NULL, NULL); 145*7698c759SSepherosa Ziehau MODULE_DEPEND(memtemp_e5, pci, 1, 1, 1); 146*7698c759SSepherosa Ziehau 147*7698c759SSepherosa Ziehau static int 148*7698c759SSepherosa Ziehau memtemp_e5_probe(device_t dev) 149*7698c759SSepherosa Ziehau { 150*7698c759SSepherosa Ziehau const struct memtemp_e5_type *t; 151*7698c759SSepherosa Ziehau uint16_t vid, did; 152*7698c759SSepherosa Ziehau int slot, func; 153*7698c759SSepherosa Ziehau 154*7698c759SSepherosa Ziehau vid = pci_get_vendor(dev); 155*7698c759SSepherosa Ziehau if (vid != PCI_E5_VID_ID) 156*7698c759SSepherosa Ziehau return ENXIO; 157*7698c759SSepherosa Ziehau 158*7698c759SSepherosa Ziehau did = pci_get_device(dev); 159*7698c759SSepherosa Ziehau slot = pci_get_slot(dev); 160*7698c759SSepherosa Ziehau func = pci_get_function(dev); 161*7698c759SSepherosa Ziehau 162*7698c759SSepherosa Ziehau for (t = memtemp_types; t->desc != NULL; ++t) { 163*7698c759SSepherosa Ziehau if (t->did == did && t->slot == slot && t->func == func) { 164*7698c759SSepherosa Ziehau struct memtemp_e5_softc *sc = device_get_softc(dev); 165*7698c759SSepherosa Ziehau char desc[128]; 166*7698c759SSepherosa Ziehau uint32_t val; 167*7698c759SSepherosa Ziehau int node, dimm; 168*7698c759SSepherosa Ziehau 169*7698c759SSepherosa Ziehau /* Check CPGC vid/did */ 170*7698c759SSepherosa Ziehau if (IMC_CPGC_READ_2(dev, PCIR_VENDOR) != 171*7698c759SSepherosa Ziehau PCI_E5_VID_ID || 172*7698c759SSepherosa Ziehau IMC_CPGC_READ_2(dev, PCIR_DEVICE) != 173*7698c759SSepherosa Ziehau PCI_E5_IMC_CPGC_DID_ID) 174*7698c759SSepherosa Ziehau break; 175*7698c759SSepherosa Ziehau 176*7698c759SSepherosa Ziehau /* Is this channel disabled */ 177*7698c759SSepherosa Ziehau val = IMC_CPGC_READ_4(dev, PCI_E5_IMC_CPGC_MCMTR); 178*7698c759SSepherosa Ziehau if (val & PCI_E5_IMC_CPGC_MCMTR_CHN_DISABLE(t->chan)) 179*7698c759SSepherosa Ziehau break; 180*7698c759SSepherosa Ziehau 181*7698c759SSepherosa Ziehau /* Check CTAD vid/did */ 182*7698c759SSepherosa Ziehau if (IMC_CTAD_READ_2(dev, t->chan, PCIR_VENDOR) != 183*7698c759SSepherosa Ziehau PCI_E5_VID_ID || 184*7698c759SSepherosa Ziehau IMC_CTAD_READ_2(dev, t->chan, PCIR_DEVICE) != 185*7698c759SSepherosa Ziehau PCI_E5_IMC_CTAD_DID_ID(t->chan)) 186*7698c759SSepherosa Ziehau break; 187*7698c759SSepherosa Ziehau 188*7698c759SSepherosa Ziehau /* Are there any DIMMs populated? */ 189*7698c759SSepherosa Ziehau for (dimm = 0; dimm < PCI_E5_IMC_DIMM_MAX; ++dimm) { 190*7698c759SSepherosa Ziehau val = IMC_CTAD_READ_4(dev, t->chan, 191*7698c759SSepherosa Ziehau PCI_E5_IMC_CTAD_DIMMMTR(dimm)); 192*7698c759SSepherosa Ziehau if (val & PCI_E5_IMC_CTAD_DIMMMTR_DIMM_POP) 193*7698c759SSepherosa Ziehau break; 194*7698c759SSepherosa Ziehau } 195*7698c759SSepherosa Ziehau if (dimm == PCI_E5_IMC_DIMM_MAX) 196*7698c759SSepherosa Ziehau break; 197*7698c759SSepherosa Ziehau 198*7698c759SSepherosa Ziehau /* Check UBOX vid/did */ 199*7698c759SSepherosa Ziehau if (UBOX_READ_2(dev, PCIR_VENDOR) != PCI_E5_VID_ID || 200*7698c759SSepherosa Ziehau UBOX_READ_2(dev, PCIR_DEVICE) != 201*7698c759SSepherosa Ziehau PCI_E5_UBOX0_DID_ID) 202*7698c759SSepherosa Ziehau break; 203*7698c759SSepherosa Ziehau 204*7698c759SSepherosa Ziehau val = UBOX_READ_4(dev, PCI_E5_UBOX0_CPUNODEID); 205*7698c759SSepherosa Ziehau node = __SHIFTOUT(val, 206*7698c759SSepherosa Ziehau PCI_E5_UBOX0_CPUNODEID_LCLNODEID); 207*7698c759SSepherosa Ziehau 208*7698c759SSepherosa Ziehau ksnprintf(desc, sizeof(desc), "%s node%d channel%d", 209*7698c759SSepherosa Ziehau t->desc, node, t->chan); 210*7698c759SSepherosa Ziehau device_set_desc_copy(dev, desc); 211*7698c759SSepherosa Ziehau 212*7698c759SSepherosa Ziehau sc->temp_chan = t->chan; 213*7698c759SSepherosa Ziehau sc->temp_node = node; 214*7698c759SSepherosa Ziehau 215*7698c759SSepherosa Ziehau return 0; 216*7698c759SSepherosa Ziehau } 217*7698c759SSepherosa Ziehau } 218*7698c759SSepherosa Ziehau return ENXIO; 219*7698c759SSepherosa Ziehau } 220*7698c759SSepherosa Ziehau 221*7698c759SSepherosa Ziehau static int 222*7698c759SSepherosa Ziehau memtemp_e5_attach(device_t dev) 223*7698c759SSepherosa Ziehau { 224*7698c759SSepherosa Ziehau struct memtemp_e5_softc *sc = device_get_softc(dev); 225*7698c759SSepherosa Ziehau int dimm; 226*7698c759SSepherosa Ziehau 227*7698c759SSepherosa Ziehau sc->temp_dev = dev; 228*7698c759SSepherosa Ziehau TAILQ_INIT(&sc->temp_dimm); 229*7698c759SSepherosa Ziehau 230*7698c759SSepherosa Ziehau for (dimm = 0; dimm < PCI_E5_IMC_DIMM_MAX; ++dimm) { 231*7698c759SSepherosa Ziehau struct memtemp_e5_dimm *dimm_sc; 232*7698c759SSepherosa Ziehau uint32_t dimmmtr; 233*7698c759SSepherosa Ziehau 234*7698c759SSepherosa Ziehau dimmmtr = IMC_CTAD_READ_4(sc->temp_dev, sc->temp_chan, 235*7698c759SSepherosa Ziehau PCI_E5_IMC_CTAD_DIMMMTR(dimm)); 236*7698c759SSepherosa Ziehau 237*7698c759SSepherosa Ziehau if ((dimmmtr & PCI_E5_IMC_CTAD_DIMMMTR_DIMM_POP) == 0) 238*7698c759SSepherosa Ziehau continue; 239*7698c759SSepherosa Ziehau 240*7698c759SSepherosa Ziehau dimm_sc = kmalloc(sizeof(*dimm_sc), M_DEVBUF, 241*7698c759SSepherosa Ziehau M_WAITOK | M_ZERO); 242*7698c759SSepherosa Ziehau dimm_sc->dimm_id = dimm; 243*7698c759SSepherosa Ziehau dimm_sc->dimm_parent = sc; 244*7698c759SSepherosa Ziehau dimm_sc->dimm_extid = 245*7698c759SSepherosa Ziehau (sc->temp_node * PCI_E5_IMC_CHN_MAX * PCI_E5_IMC_DIMM_MAX) + 246*7698c759SSepherosa Ziehau (sc->temp_chan * PCI_E5_IMC_DIMM_MAX) + dimm; 247*7698c759SSepherosa Ziehau 248*7698c759SSepherosa Ziehau ksnprintf(dimm_sc->dimm_sensordev.xname, 249*7698c759SSepherosa Ziehau sizeof(dimm_sc->dimm_sensordev.xname), 250*7698c759SSepherosa Ziehau "dimm%d", dimm_sc->dimm_extid); 251*7698c759SSepherosa Ziehau dimm_sc->dimm_sensor.type = SENSOR_TEMP; 252*7698c759SSepherosa Ziehau sensor_attach(&dimm_sc->dimm_sensordev, &dimm_sc->dimm_sensor); 253*7698c759SSepherosa Ziehau if (sensor_task_register(dimm_sc, memtemp_e5_sensor_task, 2)) { 254*7698c759SSepherosa Ziehau device_printf(sc->temp_dev, "DIMM%d sensor task " 255*7698c759SSepherosa Ziehau "register failed\n", dimm); 256*7698c759SSepherosa Ziehau kfree(dimm_sc, M_DEVBUF); 257*7698c759SSepherosa Ziehau continue; 258*7698c759SSepherosa Ziehau } 259*7698c759SSepherosa Ziehau sensordev_install(&dimm_sc->dimm_sensordev); 260*7698c759SSepherosa Ziehau 261*7698c759SSepherosa Ziehau TAILQ_INSERT_TAIL(&sc->temp_dimm, dimm_sc, dimm_link); 262*7698c759SSepherosa Ziehau } 263*7698c759SSepherosa Ziehau return 0; 264*7698c759SSepherosa Ziehau } 265*7698c759SSepherosa Ziehau 266*7698c759SSepherosa Ziehau static int 267*7698c759SSepherosa Ziehau memtemp_e5_detach(device_t dev) 268*7698c759SSepherosa Ziehau { 269*7698c759SSepherosa Ziehau struct memtemp_e5_softc *sc = device_get_softc(dev); 270*7698c759SSepherosa Ziehau struct memtemp_e5_dimm *dimm_sc; 271*7698c759SSepherosa Ziehau 272*7698c759SSepherosa Ziehau while ((dimm_sc = TAILQ_FIRST(&sc->temp_dimm)) != NULL) { 273*7698c759SSepherosa Ziehau TAILQ_REMOVE(&sc->temp_dimm, dimm_sc, dimm_link); 274*7698c759SSepherosa Ziehau 275*7698c759SSepherosa Ziehau sensordev_deinstall(&dimm_sc->dimm_sensordev); 276*7698c759SSepherosa Ziehau sensor_task_unregister(dimm_sc); 277*7698c759SSepherosa Ziehau 278*7698c759SSepherosa Ziehau kfree(dimm_sc, M_DEVBUF); 279*7698c759SSepherosa Ziehau } 280*7698c759SSepherosa Ziehau return 0; 281*7698c759SSepherosa Ziehau } 282*7698c759SSepherosa Ziehau 283*7698c759SSepherosa Ziehau static void 284*7698c759SSepherosa Ziehau memtemp_e5_sensor_task(void *xdimm_sc) 285*7698c759SSepherosa Ziehau { 286*7698c759SSepherosa Ziehau struct memtemp_e5_dimm *dimm_sc = xdimm_sc; 287*7698c759SSepherosa Ziehau struct ksensor *sensor = &dimm_sc->dimm_sensor; 288*7698c759SSepherosa Ziehau uint32_t val; 289*7698c759SSepherosa Ziehau int temp; 290*7698c759SSepherosa Ziehau 291*7698c759SSepherosa Ziehau val = pci_read_config(dimm_sc->dimm_parent->temp_dev, 292*7698c759SSepherosa Ziehau PCI_E5_IMC_THERMAL_DIMMTEMPSTAT(dimm_sc->dimm_id), 4); 293*7698c759SSepherosa Ziehau temp = __SHIFTOUT(val, PCI_E5_IMC_THERMAL_DIMMTEMPSTAT_TEMP); 294*7698c759SSepherosa Ziehau 295*7698c759SSepherosa Ziehau sensor->flags &= ~SENSOR_FINVALID; 296*7698c759SSepherosa Ziehau sensor->value = (temp * 1000000) + 273150000; 297*7698c759SSepherosa Ziehau } 298