xref: /dflybsd-src/sys/dev/powermng/memtemp/memtemp_e5.c (revision acbc630d902fb9fc35d9b4ac0944b2edfb1ec681)
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