xref: /illumos-gate/usr/src/uts/common/io/igb/igb_sensor.c (revision 1045e13a)
12509632aSRobert Mustacchi /*
22509632aSRobert Mustacchi  * This file and its contents are supplied under the terms of the
32509632aSRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
42509632aSRobert Mustacchi  * You may only use this file in accordance with the terms of version
52509632aSRobert Mustacchi  * 1.0 of the CDDL.
62509632aSRobert Mustacchi  *
72509632aSRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
82509632aSRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
92509632aSRobert Mustacchi  * http://www.illumos.org/license/CDDL.
102509632aSRobert Mustacchi  */
112509632aSRobert Mustacchi 
122509632aSRobert Mustacchi /*
132509632aSRobert Mustacchi  * Copyright 2020 Oxide Computer Company
142509632aSRobert Mustacchi  */
152509632aSRobert Mustacchi 
162509632aSRobert Mustacchi /*
172509632aSRobert Mustacchi  * Handle and report sensors found on some igb parts.
182509632aSRobert Mustacchi  *
192509632aSRobert Mustacchi  * The Intel I350 has a built-in thermal sensor diode and an optional External
202509632aSRobert Mustacchi  * Thermal Sensor configuration. This external configuration is provided through
212509632aSRobert Mustacchi  * an optional space in the NVM and allows for up to 4 external sensors to be
222509632aSRobert Mustacchi  * defined. Currently, the only defined external thermal sensor is the Microchip
232509632aSRobert Mustacchi  * EMC 1413. As of this time, we haven't encountered a device that uses the EMC
242509632aSRobert Mustacchi  * 1413 in the wild, so while the definitions here are present, that is stubbed
252509632aSRobert Mustacchi  * out for the time.
262509632aSRobert Mustacchi  *
272509632aSRobert Mustacchi  * When accessing the internal sensor, the I350 Datasheet requires that we take
282509632aSRobert Mustacchi  * software/firmware semaphore before proceeding.
292509632aSRobert Mustacchi  */
302509632aSRobert Mustacchi 
312509632aSRobert Mustacchi #include "igb_sw.h"
322509632aSRobert Mustacchi #include <sys/sensors.h>
332509632aSRobert Mustacchi #include <sys/bitmap.h>
342509632aSRobert Mustacchi 
352509632aSRobert Mustacchi /*
362509632aSRobert Mustacchi  * Thermal register values.
372509632aSRobert Mustacchi  */
382509632aSRobert Mustacchi #define	E1000_THMJT_TEMP(x)	BITX(x, 8, 0)
392509632aSRobert Mustacchi #define	E1000_THMJT_VALID(x)	BITX(x, 31, 31)
402509632aSRobert Mustacchi #define	E1000_THMJT_RESOLUTION	1
412509632aSRobert Mustacchi #define	E1000_THMJT_PRECISION	5
422509632aSRobert Mustacchi 
432509632aSRobert Mustacchi /*
442509632aSRobert Mustacchi  * Misc. definitions required for accessing the NVM space.
452509632aSRobert Mustacchi  */
462509632aSRobert Mustacchi #define	IGB_NVM_ETS_CFG	0x3e
472509632aSRobert Mustacchi #define	IGB_NVM_ETS_CFG_NSENSORS(x)	BITX(x, 2, 0)
482509632aSRobert Mustacchi #define	IGB_NVM_ETS_CFG_TYPE(x)		BITX(x, 5, 3)
492509632aSRobert Mustacchi #define	IGB_NVM_ETS_CFG_TYPE_EMC1413	0
502509632aSRobert Mustacchi 
512509632aSRobert Mustacchi #define	IGB_NVM_ETS_SENSOR_LOC(x)	BITX(x, 13, 10)
522509632aSRobert Mustacchi #define	IGB_NVM_ETS_SENSOR_INDEX(x)	BITX(x, 9, 8)
532509632aSRobert Mustacchi #define	IGB_NVM_ETS_SENSOR_THRESH(x)	BITX(x, 7, 0)
542509632aSRobert Mustacchi 
552509632aSRobert Mustacchi #define	IGB_ETS_I2C_ADDRESS	0xf8
562509632aSRobert Mustacchi 
572509632aSRobert Mustacchi /*
582509632aSRobert Mustacchi  * These definitions come from the Microchip datasheet for the thermal diode
592509632aSRobert Mustacchi  * sensor defined by the external spec. These parts have an accuracy of 1 degree
602509632aSRobert Mustacchi  * and a granularity of 1/8th of a degree.
612509632aSRobert Mustacchi  */
622509632aSRobert Mustacchi #define	EMC1413_REG_CFG			0x03
632509632aSRobert Mustacchi #define	EMC1413_REG_CFG_RANGE		(1 << 2)
642509632aSRobert Mustacchi #define	EMC1413_RANGE_ADJ		(-64)
652509632aSRobert Mustacchi #define	EMC1413_REG_INT_DIODE_HI	0x00
662509632aSRobert Mustacchi #define	EMC1413_REG_INT_DIODE_LO	0x29
672509632aSRobert Mustacchi #define	EMC1413_REG_EXT1_DIODE_HI	0x01
682509632aSRobert Mustacchi #define	EMC1413_REG_EXT1_DIODE_LO	0x10
692509632aSRobert Mustacchi #define	EMC1413_REG_EXT2_DIODE_HI	0x23
702509632aSRobert Mustacchi #define	EMC1413_REG_EXT2_DIODE_LO	0x24
712509632aSRobert Mustacchi #define	EMC1413_REG_EXT3_DIODE_HI	0x2a
722509632aSRobert Mustacchi #define	EMC1413_REG_EXT3_DIODE_LO	0x2b
732509632aSRobert Mustacchi 
742509632aSRobert Mustacchi static int
igb_sensor_reg_temperature(void * arg,sensor_ioctl_scalar_t * scalar)75*1045e13aSRobert Mustacchi igb_sensor_reg_temperature(void *arg, sensor_ioctl_scalar_t *scalar)
762509632aSRobert Mustacchi {
772509632aSRobert Mustacchi 	igb_t *igb = arg;
782509632aSRobert Mustacchi 	uint32_t reg;
792509632aSRobert Mustacchi 
802509632aSRobert Mustacchi 	if (igb->hw.mac.ops.acquire_swfw_sync(&igb->hw, E1000_SWFW_PWRTS_SM) !=
812509632aSRobert Mustacchi 	    E1000_SUCCESS) {
822509632aSRobert Mustacchi 		return (EIO);
832509632aSRobert Mustacchi 	}
842509632aSRobert Mustacchi 	reg = E1000_READ_REG(&igb->hw, E1000_THMJT);
852509632aSRobert Mustacchi 	igb->hw.mac.ops.release_swfw_sync(&igb->hw, E1000_SWFW_PWRTS_SM);
862509632aSRobert Mustacchi 	if (E1000_THMJT_VALID(reg) == 0) {
872509632aSRobert Mustacchi 		return (EIO);
882509632aSRobert Mustacchi 	}
892509632aSRobert Mustacchi 
90*1045e13aSRobert Mustacchi 	scalar->sis_unit = SENSOR_UNIT_CELSIUS;
91*1045e13aSRobert Mustacchi 	scalar->sis_gran = E1000_THMJT_RESOLUTION;
92*1045e13aSRobert Mustacchi 	scalar->sis_prec = E1000_THMJT_PRECISION;
93*1045e13aSRobert Mustacchi 	scalar->sis_value = E1000_THMJT_TEMP(reg);
942509632aSRobert Mustacchi 
952509632aSRobert Mustacchi 	return (0);
962509632aSRobert Mustacchi }
972509632aSRobert Mustacchi 
982509632aSRobert Mustacchi static const ksensor_ops_t igb_sensor_reg_ops = {
992509632aSRobert Mustacchi 	.kso_kind = ksensor_kind_temperature,
100*1045e13aSRobert Mustacchi 	.kso_scalar = igb_sensor_reg_temperature
1012509632aSRobert Mustacchi };
1022509632aSRobert Mustacchi 
1032509632aSRobert Mustacchi static boolean_t
igb_sensors_create_minors(igb_t * igb)1042509632aSRobert Mustacchi igb_sensors_create_minors(igb_t *igb)
1052509632aSRobert Mustacchi {
1062509632aSRobert Mustacchi 	int ret;
1072509632aSRobert Mustacchi 	igb_sensors_t *sp = &igb->igb_sensors;
1082509632aSRobert Mustacchi 
109*1045e13aSRobert Mustacchi 	if ((ret = ksensor_create_scalar_pcidev(igb->dip,
110*1045e13aSRobert Mustacchi 	    SENSOR_KIND_TEMPERATURE, &igb_sensor_reg_ops, igb, "builtin",
111*1045e13aSRobert Mustacchi 	    &sp->isn_reg_ksensor)) != 0) {
1122509632aSRobert Mustacchi 		igb_log(igb, IGB_LOG_ERROR, "failed to create main sensor: %d",
1132509632aSRobert Mustacchi 		    ret);
1142509632aSRobert Mustacchi 		return (B_FALSE);
1152509632aSRobert Mustacchi 	}
1162509632aSRobert Mustacchi 
1172509632aSRobert Mustacchi 	return (B_TRUE);
1182509632aSRobert Mustacchi }
1192509632aSRobert Mustacchi 
1202509632aSRobert Mustacchi static boolean_t
igb_sensors_init_ets(igb_t * igb,uint_t ets_off,uint_t index)1212509632aSRobert Mustacchi igb_sensors_init_ets(igb_t *igb, uint_t ets_off, uint_t index)
1222509632aSRobert Mustacchi {
1232509632aSRobert Mustacchi 	uint16_t val;
1242509632aSRobert Mustacchi 	int ret;
1252509632aSRobert Mustacchi 	igb_sensors_t *sensors = &igb->igb_sensors;
1262509632aSRobert Mustacchi 	igb_ets_t *etsp = &sensors->isn_ets[sensors->isn_nents];
1272509632aSRobert Mustacchi 	igb_ets_loc_t loc;
1282509632aSRobert Mustacchi 
1292509632aSRobert Mustacchi 	if ((ret = e1000_read_nvm(&igb->hw, ets_off, 1, &val)) !=
1302509632aSRobert Mustacchi 	    E1000_SUCCESS) {
1312509632aSRobert Mustacchi 		igb_log(igb, IGB_LOG_ERROR, "failed to read ETS word "
1322509632aSRobert Mustacchi 		    "at offset 0x%x: error %d", ets_off, ret);
1332509632aSRobert Mustacchi 		return (B_FALSE);
1342509632aSRobert Mustacchi 	}
1352509632aSRobert Mustacchi 
1362509632aSRobert Mustacchi 	/*
1372509632aSRobert Mustacchi 	 * The data sheet says that if the location is listed as N/A, then we
1382509632aSRobert Mustacchi 	 * should not display this sensor. In this case, we just skip it.
1392509632aSRobert Mustacchi 	 */
1402509632aSRobert Mustacchi 	loc = IGB_NVM_ETS_SENSOR_LOC(val);
1412509632aSRobert Mustacchi 	if (loc == IGB_ETS_LOC_NA) {
1422509632aSRobert Mustacchi 		return (B_TRUE);
1432509632aSRobert Mustacchi 	}
1442509632aSRobert Mustacchi 
1452509632aSRobert Mustacchi 	etsp->iet_loc = loc;
1462509632aSRobert Mustacchi 	etsp->iet_index = IGB_NVM_ETS_SENSOR_INDEX(val);
1472509632aSRobert Mustacchi 	etsp->iet_thresh = IGB_NVM_ETS_SENSOR_THRESH(val);
1482509632aSRobert Mustacchi 	sensors->isn_nents++;
1492509632aSRobert Mustacchi 
1502509632aSRobert Mustacchi 	return (B_TRUE);
1512509632aSRobert Mustacchi }
1522509632aSRobert Mustacchi 
1532509632aSRobert Mustacchi void
igb_init_sensors(igb_t * igb)1542509632aSRobert Mustacchi igb_init_sensors(igb_t *igb)
1552509632aSRobert Mustacchi {
1562509632aSRobert Mustacchi 	struct e1000_hw *hw = &igb->hw;
1572509632aSRobert Mustacchi 	uint16_t ets_off;
1582509632aSRobert Mustacchi 
1592509632aSRobert Mustacchi 	/*
1602509632aSRobert Mustacchi 	 * Only the I350 supports the thermal temperature sensor values. This is
1612509632aSRobert Mustacchi 	 * device-wide, so only enumerate on bus zero.
1622509632aSRobert Mustacchi 	 */
1632509632aSRobert Mustacchi 	hw = &igb->hw;
1642509632aSRobert Mustacchi 	if (hw->mac.type != e1000_i350 || hw->bus.func != 0) {
1652509632aSRobert Mustacchi 		return;
1662509632aSRobert Mustacchi 	}
1672509632aSRobert Mustacchi 
1682509632aSRobert Mustacchi 	ets_off = 0xffff;
1692509632aSRobert Mustacchi 	(void) e1000_read_nvm(hw, IGB_NVM_ETS_CFG, 1, &ets_off);
1702509632aSRobert Mustacchi 	if (ets_off != 0 && ets_off != 0xffff) {
1712509632aSRobert Mustacchi 		int ret;
1722509632aSRobert Mustacchi 		uint_t nents, i;
1732509632aSRobert Mustacchi 		uint16_t val;
1742509632aSRobert Mustacchi 
1752509632aSRobert Mustacchi 		/*
1762509632aSRobert Mustacchi 		 * Swallow the fact that we can't read the ETS config.
1772509632aSRobert Mustacchi 		 */
1782509632aSRobert Mustacchi 		if ((ret = e1000_read_nvm(hw, ets_off, 1, &val)) !=
1792509632aSRobert Mustacchi 		    E1000_SUCCESS) {
1802509632aSRobert Mustacchi 			igb_log(igb, IGB_LOG_ERROR, "failed to read ETS word "
1812509632aSRobert Mustacchi 			    "at offset 0x%x: error %d", ets_off, ret);
1822509632aSRobert Mustacchi 			return;
1832509632aSRobert Mustacchi 		}
1842509632aSRobert Mustacchi 
1852509632aSRobert Mustacchi 		/*
1862509632aSRobert Mustacchi 		 * If we don't find this, assume we can't use the external
1872509632aSRobert Mustacchi 		 * sensor either.
1882509632aSRobert Mustacchi 		 */
1892509632aSRobert Mustacchi 		if (IGB_NVM_ETS_CFG_TYPE(val) != IGB_NVM_ETS_CFG_TYPE_EMC1413) {
1902509632aSRobert Mustacchi 			return;
1912509632aSRobert Mustacchi 		}
1922509632aSRobert Mustacchi 
1932509632aSRobert Mustacchi 		nents = IGB_NVM_ETS_CFG_NSENSORS(val);
1942509632aSRobert Mustacchi 		if (nents > IGB_ETS_MAX) {
1952509632aSRobert Mustacchi 			igb_log(igb, IGB_LOG_ERROR, "firmware NVM ETS "
1962509632aSRobert Mustacchi 			    "configuration has more entries (%d) than allowed",
1972509632aSRobert Mustacchi 			    nents);
1982509632aSRobert Mustacchi 			nents = IGB_ETS_MAX;
1992509632aSRobert Mustacchi 		}
2002509632aSRobert Mustacchi 
2012509632aSRobert Mustacchi 		for (i = 0; i < nents; i++) {
2022509632aSRobert Mustacchi 			if (!igb_sensors_init_ets(igb, ets_off, i)) {
2032509632aSRobert Mustacchi 				return;
2042509632aSRobert Mustacchi 			}
2052509632aSRobert Mustacchi 		}
2062509632aSRobert Mustacchi 	}
2072509632aSRobert Mustacchi 
2082509632aSRobert Mustacchi 	if (!igb_sensors_create_minors(igb)) {
2092509632aSRobert Mustacchi 		(void) ksensor_remove(igb->dip, KSENSOR_ALL_IDS);
2102509632aSRobert Mustacchi 		return;
2112509632aSRobert Mustacchi 	}
2122509632aSRobert Mustacchi 
2132509632aSRobert Mustacchi 	igb->igb_sensors.isn_valid = B_TRUE;
2142509632aSRobert Mustacchi }
2152509632aSRobert Mustacchi 
2162509632aSRobert Mustacchi void
igb_fini_sensors(igb_t * igb)2172509632aSRobert Mustacchi igb_fini_sensors(igb_t *igb)
2182509632aSRobert Mustacchi {
2192509632aSRobert Mustacchi 	if (igb->igb_sensors.isn_valid) {
2202509632aSRobert Mustacchi 		(void) ksensor_remove(igb->dip, KSENSOR_ALL_IDS);
2212509632aSRobert Mustacchi 		igb->igb_sensors.isn_valid = B_FALSE;
2222509632aSRobert Mustacchi 	}
2232509632aSRobert Mustacchi }
224