17698c759SSepherosa Ziehau /* 27698c759SSepherosa Ziehau * Copyright (c) 2015 The DragonFly Project. All rights reserved. 37698c759SSepherosa Ziehau * 47698c759SSepherosa Ziehau * This code is derived from software contributed to The DragonFly Project 57698c759SSepherosa Ziehau * by Sepherosa Ziehau <sepherosa@gmail.com> 67698c759SSepherosa Ziehau * 77698c759SSepherosa Ziehau * Redistribution and use in source and binary forms, with or without 87698c759SSepherosa Ziehau * modification, are permitted provided that the following conditions 97698c759SSepherosa Ziehau * are met: 107698c759SSepherosa Ziehau * 117698c759SSepherosa Ziehau * 1. Redistributions of source code must retain the above copyright 127698c759SSepherosa Ziehau * notice, this list of conditions and the following disclaimer. 137698c759SSepherosa Ziehau * 2. Redistributions in binary form must reproduce the above copyright 147698c759SSepherosa Ziehau * notice, this list of conditions and the following disclaimer in 157698c759SSepherosa Ziehau * the documentation and/or other materials provided with the 167698c759SSepherosa Ziehau * distribution. 177698c759SSepherosa Ziehau * 3. Neither the name of The DragonFly Project nor the names of its 187698c759SSepherosa Ziehau * contributors may be used to endorse or promote products derived 197698c759SSepherosa Ziehau * from this software without specific, prior written permission. 207698c759SSepherosa Ziehau * 217698c759SSepherosa Ziehau * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 227698c759SSepherosa Ziehau * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 237698c759SSepherosa Ziehau * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 247698c759SSepherosa Ziehau * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 257698c759SSepherosa Ziehau * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 267698c759SSepherosa Ziehau * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 277698c759SSepherosa Ziehau * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 287698c759SSepherosa Ziehau * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 297698c759SSepherosa Ziehau * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 307698c759SSepherosa Ziehau * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 317698c759SSepherosa Ziehau * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 327698c759SSepherosa Ziehau * SUCH DAMAGE. 337698c759SSepherosa Ziehau */ 347698c759SSepherosa Ziehau 357698c759SSepherosa Ziehau #include <sys/param.h> 367698c759SSepherosa Ziehau #include <sys/systm.h> 377698c759SSepherosa Ziehau #include <sys/bitops.h> 387698c759SSepherosa Ziehau #include <sys/bus.h> 397698c759SSepherosa Ziehau #include <sys/kernel.h> 407698c759SSepherosa Ziehau #include <sys/malloc.h> 417698c759SSepherosa Ziehau #include <sys/sensors.h> 427698c759SSepherosa Ziehau #include <sys/sysctl.h> 437698c759SSepherosa Ziehau 447698c759SSepherosa Ziehau #include <bus/pci/pcivar.h> 457698c759SSepherosa Ziehau #include <bus/pci/pcireg.h> 467698c759SSepherosa Ziehau #include <bus/pci/pcibus.h> 477698c759SSepherosa Ziehau #include <bus/pci/pci_cfgreg.h> 487698c759SSepherosa Ziehau #include <bus/pci/pcib_private.h> 497698c759SSepherosa Ziehau 507698c759SSepherosa Ziehau #include "pcib_if.h" 517698c759SSepherosa Ziehau 520c543cddSSepherosa Ziehau #include <dev/misc/ecc/e5_imc_reg.h> 530c543cddSSepherosa Ziehau #include <dev/misc/ecc/e5_imc_var.h> 547698c759SSepherosa Ziehau 557698c759SSepherosa Ziehau struct memtemp_e5_softc; 567698c759SSepherosa Ziehau 577698c759SSepherosa Ziehau struct memtemp_e5_dimm { 587698c759SSepherosa Ziehau TAILQ_ENTRY(memtemp_e5_dimm) dimm_link; 597698c759SSepherosa Ziehau struct ksensordev dimm_sensordev; 607698c759SSepherosa Ziehau struct ksensor dimm_sensor; 617698c759SSepherosa Ziehau struct memtemp_e5_softc *dimm_parent; 627698c759SSepherosa Ziehau int dimm_id; 637698c759SSepherosa Ziehau int dimm_extid; 647698c759SSepherosa Ziehau }; 657698c759SSepherosa Ziehau 667698c759SSepherosa Ziehau struct memtemp_e5_softc { 677698c759SSepherosa Ziehau device_t temp_dev; 680c543cddSSepherosa Ziehau const struct e5_imc_chan *temp_chan; 697698c759SSepherosa Ziehau int temp_node; 707698c759SSepherosa Ziehau TAILQ_HEAD(, memtemp_e5_dimm) temp_dimm; 717698c759SSepherosa Ziehau }; 727698c759SSepherosa Ziehau 737698c759SSepherosa Ziehau static int memtemp_e5_probe(device_t); 747698c759SSepherosa Ziehau static int memtemp_e5_attach(device_t); 757698c759SSepherosa Ziehau static int memtemp_e5_detach(device_t); 767698c759SSepherosa Ziehau 777698c759SSepherosa Ziehau static void memtemp_e5_sensor_task(void *); 787698c759SSepherosa Ziehau 790c543cddSSepherosa Ziehau #define MEMTEMP_E5_CHAN(v, imc, c, c_ext) \ 807698c759SSepherosa Ziehau { \ 810c543cddSSepherosa Ziehau .did = PCI_E5V##v##_IMC##imc##_THERMAL_CHN##c##_DID_ID, \ 820c543cddSSepherosa Ziehau .slot = PCISLOT_E5V##v##_IMC##imc##_THERMAL_CHN##c, \ 830c543cddSSepherosa Ziehau .func = PCIFUNC_E5V##v##_IMC##imc##_THERMAL_CHN##c, \ 840c543cddSSepherosa Ziehau .desc = "Intel E5 v" #v " memory thermal sensor", \ 850c543cddSSepherosa Ziehau \ 860c543cddSSepherosa Ziehau E5_IMC_CHAN_FIELDS(v, imc, c, c_ext) \ 877698c759SSepherosa Ziehau } 887698c759SSepherosa Ziehau 890c543cddSSepherosa Ziehau #define MEMTEMP_E5_CHAN_V2(c) MEMTEMP_E5_CHAN(2, 0, c, c) 90*acbc630dSSepherosa Ziehau #define MEMTEMP_E5_CHAN_IMC0_V3(c) MEMTEMP_E5_CHAN(3, 0, c, c) 91*acbc630dSSepherosa Ziehau #define MEMTEMP_E5_CHAN_IMC1_V3(c, c_ext) \ 92*acbc630dSSepherosa Ziehau MEMTEMP_E5_CHAN(3, 1, c, c_ext) 930c543cddSSepherosa Ziehau #define MEMTEMP_E5_CHAN_END E5_IMC_CHAN_END 947698c759SSepherosa Ziehau 950c543cddSSepherosa Ziehau static const struct e5_imc_chan memtemp_e5_chans[] = { 960c543cddSSepherosa Ziehau MEMTEMP_E5_CHAN_V2(0), 970c543cddSSepherosa Ziehau MEMTEMP_E5_CHAN_V2(1), 980c543cddSSepherosa Ziehau MEMTEMP_E5_CHAN_V2(2), 990c543cddSSepherosa Ziehau MEMTEMP_E5_CHAN_V2(3), 1007698c759SSepherosa Ziehau 101*acbc630dSSepherosa Ziehau MEMTEMP_E5_CHAN_IMC0_V3(0), 102*acbc630dSSepherosa Ziehau MEMTEMP_E5_CHAN_IMC0_V3(1), 103*acbc630dSSepherosa Ziehau MEMTEMP_E5_CHAN_IMC0_V3(2), 104*acbc630dSSepherosa Ziehau MEMTEMP_E5_CHAN_IMC0_V3(3), 105*acbc630dSSepherosa Ziehau MEMTEMP_E5_CHAN_IMC1_V3(0, 2), /* IMC1 chan0 -> channel2 */ 106*acbc630dSSepherosa Ziehau MEMTEMP_E5_CHAN_IMC1_V3(1, 3), /* IMC1 chan1 -> channel3 */ 107*acbc630dSSepherosa Ziehau 1080c543cddSSepherosa Ziehau MEMTEMP_E5_CHAN_END 1097698c759SSepherosa Ziehau }; 1107698c759SSepherosa Ziehau 1110c543cddSSepherosa Ziehau #undef MEMTEMP_E5_CHAN_END 1120c543cddSSepherosa Ziehau #undef MEMTEMP_E5_CHAN_V2 1130c543cddSSepherosa Ziehau #undef MEMTEMP_E5_CHAN 1147698c759SSepherosa Ziehau 1157698c759SSepherosa Ziehau static device_method_t memtemp_e5_methods[] = { 1167698c759SSepherosa Ziehau /* Device interface */ 1177698c759SSepherosa Ziehau DEVMETHOD(device_probe, memtemp_e5_probe), 1187698c759SSepherosa Ziehau DEVMETHOD(device_attach, memtemp_e5_attach), 1197698c759SSepherosa Ziehau DEVMETHOD(device_detach, memtemp_e5_detach), 1207698c759SSepherosa Ziehau DEVMETHOD(device_shutdown, bus_generic_shutdown), 1217698c759SSepherosa Ziehau DEVMETHOD(device_suspend, bus_generic_suspend), 1227698c759SSepherosa Ziehau DEVMETHOD(device_resume, bus_generic_resume), 1237698c759SSepherosa Ziehau DEVMETHOD_END 1247698c759SSepherosa Ziehau }; 1257698c759SSepherosa Ziehau 1267698c759SSepherosa Ziehau static driver_t memtemp_e5_driver = { 1277698c759SSepherosa Ziehau "memtemp", 1287698c759SSepherosa Ziehau memtemp_e5_methods, 1297698c759SSepherosa Ziehau sizeof(struct memtemp_e5_softc) 1307698c759SSepherosa Ziehau }; 1317698c759SSepherosa Ziehau static devclass_t memtemp_devclass; 1327698c759SSepherosa Ziehau DRIVER_MODULE(memtemp_e5, pci, memtemp_e5_driver, memtemp_devclass, NULL, NULL); 1337698c759SSepherosa Ziehau MODULE_DEPEND(memtemp_e5, pci, 1, 1, 1); 1347698c759SSepherosa Ziehau 1357698c759SSepherosa Ziehau static int 1367698c759SSepherosa Ziehau memtemp_e5_probe(device_t dev) 1377698c759SSepherosa Ziehau { 1380c543cddSSepherosa Ziehau const struct e5_imc_chan *c; 1397698c759SSepherosa Ziehau uint16_t vid, did; 1407698c759SSepherosa Ziehau int slot, func; 1417698c759SSepherosa Ziehau 1427698c759SSepherosa Ziehau vid = pci_get_vendor(dev); 1430c543cddSSepherosa Ziehau if (vid != PCI_E5_IMC_VID_ID) 1447698c759SSepherosa Ziehau return ENXIO; 1457698c759SSepherosa Ziehau 1467698c759SSepherosa Ziehau did = pci_get_device(dev); 1477698c759SSepherosa Ziehau slot = pci_get_slot(dev); 1487698c759SSepherosa Ziehau func = pci_get_function(dev); 1497698c759SSepherosa Ziehau 1500c543cddSSepherosa Ziehau for (c = memtemp_e5_chans; c->desc != NULL; ++c) { 1510c543cddSSepherosa Ziehau if (c->did == did && c->slot == slot && c->func == func) { 1527698c759SSepherosa Ziehau struct memtemp_e5_softc *sc = device_get_softc(dev); 1537698c759SSepherosa Ziehau char desc[128]; 1540c543cddSSepherosa Ziehau int node; 1557698c759SSepherosa Ziehau 1560c543cddSSepherosa Ziehau node = e5_imc_node_probe(dev, c); 1570c543cddSSepherosa Ziehau if (node < 0) 1587698c759SSepherosa Ziehau break; 1597698c759SSepherosa Ziehau 1607698c759SSepherosa Ziehau ksnprintf(desc, sizeof(desc), "%s node%d channel%d", 1610c543cddSSepherosa Ziehau c->desc, node, c->chan_ext); 1627698c759SSepherosa Ziehau device_set_desc_copy(dev, desc); 1637698c759SSepherosa Ziehau 1640c543cddSSepherosa Ziehau sc->temp_chan = c; 1657698c759SSepherosa Ziehau sc->temp_node = node; 1667698c759SSepherosa Ziehau 1677698c759SSepherosa Ziehau return 0; 1687698c759SSepherosa Ziehau } 1697698c759SSepherosa Ziehau } 1707698c759SSepherosa Ziehau return ENXIO; 1717698c759SSepherosa Ziehau } 1727698c759SSepherosa Ziehau 1737698c759SSepherosa Ziehau static int 1747698c759SSepherosa Ziehau memtemp_e5_attach(device_t dev) 1757698c759SSepherosa Ziehau { 1767698c759SSepherosa Ziehau struct memtemp_e5_softc *sc = device_get_softc(dev); 1777698c759SSepherosa Ziehau int dimm; 1787698c759SSepherosa Ziehau 1797698c759SSepherosa Ziehau sc->temp_dev = dev; 1807698c759SSepherosa Ziehau TAILQ_INIT(&sc->temp_dimm); 1817698c759SSepherosa Ziehau 1820c543cddSSepherosa Ziehau for (dimm = 0; dimm < PCI_E5_IMC_CHN_DIMM_MAX; ++dimm) { 1837698c759SSepherosa Ziehau struct memtemp_e5_dimm *dimm_sc; 1847698c759SSepherosa Ziehau uint32_t dimmmtr; 1857698c759SSepherosa Ziehau 1867698c759SSepherosa Ziehau dimmmtr = IMC_CTAD_READ_4(sc->temp_dev, sc->temp_chan, 1877698c759SSepherosa Ziehau PCI_E5_IMC_CTAD_DIMMMTR(dimm)); 1887698c759SSepherosa Ziehau 1897698c759SSepherosa Ziehau if ((dimmmtr & PCI_E5_IMC_CTAD_DIMMMTR_DIMM_POP) == 0) 1907698c759SSepherosa Ziehau continue; 1917698c759SSepherosa Ziehau 1927698c759SSepherosa Ziehau dimm_sc = kmalloc(sizeof(*dimm_sc), M_DEVBUF, 1937698c759SSepherosa Ziehau M_WAITOK | M_ZERO); 1947698c759SSepherosa Ziehau dimm_sc->dimm_id = dimm; 1957698c759SSepherosa Ziehau dimm_sc->dimm_parent = sc; 1967698c759SSepherosa Ziehau dimm_sc->dimm_extid = 1970c543cddSSepherosa Ziehau (sc->temp_node * PCI_E5_IMC_CHN_MAX * PCI_E5_IMC_CHN_DIMM_MAX) + 1980c543cddSSepherosa Ziehau (sc->temp_chan->chan_ext * PCI_E5_IMC_CHN_DIMM_MAX) + dimm; 1997698c759SSepherosa Ziehau 2007698c759SSepherosa Ziehau ksnprintf(dimm_sc->dimm_sensordev.xname, 2017698c759SSepherosa Ziehau sizeof(dimm_sc->dimm_sensordev.xname), 2027698c759SSepherosa Ziehau "dimm%d", dimm_sc->dimm_extid); 2037698c759SSepherosa Ziehau dimm_sc->dimm_sensor.type = SENSOR_TEMP; 2047698c759SSepherosa Ziehau sensor_attach(&dimm_sc->dimm_sensordev, &dimm_sc->dimm_sensor); 2057698c759SSepherosa Ziehau if (sensor_task_register(dimm_sc, memtemp_e5_sensor_task, 2)) { 2067698c759SSepherosa Ziehau device_printf(sc->temp_dev, "DIMM%d sensor task " 2077698c759SSepherosa Ziehau "register failed\n", dimm); 2087698c759SSepherosa Ziehau kfree(dimm_sc, M_DEVBUF); 2097698c759SSepherosa Ziehau continue; 2107698c759SSepherosa Ziehau } 2117698c759SSepherosa Ziehau sensordev_install(&dimm_sc->dimm_sensordev); 2127698c759SSepherosa Ziehau 2137698c759SSepherosa Ziehau TAILQ_INSERT_TAIL(&sc->temp_dimm, dimm_sc, dimm_link); 2147698c759SSepherosa Ziehau } 2157698c759SSepherosa Ziehau return 0; 2167698c759SSepherosa Ziehau } 2177698c759SSepherosa Ziehau 2187698c759SSepherosa Ziehau static int 2197698c759SSepherosa Ziehau memtemp_e5_detach(device_t dev) 2207698c759SSepherosa Ziehau { 2217698c759SSepherosa Ziehau struct memtemp_e5_softc *sc = device_get_softc(dev); 2227698c759SSepherosa Ziehau struct memtemp_e5_dimm *dimm_sc; 2237698c759SSepherosa Ziehau 2247698c759SSepherosa Ziehau while ((dimm_sc = TAILQ_FIRST(&sc->temp_dimm)) != NULL) { 2257698c759SSepherosa Ziehau TAILQ_REMOVE(&sc->temp_dimm, dimm_sc, dimm_link); 2267698c759SSepherosa Ziehau 2277698c759SSepherosa Ziehau sensordev_deinstall(&dimm_sc->dimm_sensordev); 2287698c759SSepherosa Ziehau sensor_task_unregister(dimm_sc); 2297698c759SSepherosa Ziehau 2307698c759SSepherosa Ziehau kfree(dimm_sc, M_DEVBUF); 2317698c759SSepherosa Ziehau } 2327698c759SSepherosa Ziehau return 0; 2337698c759SSepherosa Ziehau } 2347698c759SSepherosa Ziehau 2357698c759SSepherosa Ziehau static void 2367698c759SSepherosa Ziehau memtemp_e5_sensor_task(void *xdimm_sc) 2377698c759SSepherosa Ziehau { 2387698c759SSepherosa Ziehau struct memtemp_e5_dimm *dimm_sc = xdimm_sc; 2397698c759SSepherosa Ziehau struct ksensor *sensor = &dimm_sc->dimm_sensor; 2407698c759SSepherosa Ziehau uint32_t val; 2417698c759SSepherosa Ziehau int temp; 2427698c759SSepherosa Ziehau 2437698c759SSepherosa Ziehau val = pci_read_config(dimm_sc->dimm_parent->temp_dev, 2447698c759SSepherosa Ziehau PCI_E5_IMC_THERMAL_DIMMTEMPSTAT(dimm_sc->dimm_id), 4); 2457698c759SSepherosa Ziehau temp = __SHIFTOUT(val, PCI_E5_IMC_THERMAL_DIMMTEMPSTAT_TEMP); 2467698c759SSepherosa Ziehau 2477698c759SSepherosa Ziehau sensor->flags &= ~SENSOR_FINVALID; 2487698c759SSepherosa Ziehau sensor->value = (temp * 1000000) + 273150000; 2497698c759SSepherosa Ziehau } 250