Mercurial > illumos > git > illumos-joyent
changeset 25208:b370e054b126
12835 Want support for I350 temperature sensor
Reviewed by: Ryan Zezeski <ryan@zinascii.com>
Reviewed by: Toomas Soome <toomas@me.com>
Approved by: Dan McDonald <danmcd@joyent.com>
author | Robert Mustacchi <rm@fingolfin.org> |
---|---|
date | Fri, 05 Jun 2020 09:22:48 -0700 |
parents | c4c7c8c14ae3 |
children | 86d9f1b34087 25844479db93 |
files | usr/src/uts/common/Makefile.files usr/src/uts/common/io/e1000api/e1000_defines.h usr/src/uts/common/io/igb/igb_main.c usr/src/uts/common/io/igb/igb_sensor.c usr/src/uts/common/io/igb/igb_sw.h usr/src/uts/intel/igb/Makefile |
diffstat | 6 files changed, 281 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/uts/common/Makefile.files Tue May 05 22:21:07 2020 -0700 +++ b/usr/src/uts/common/Makefile.files Fri Jun 05 09:22:48 2020 -0700 @@ -2003,7 +2003,7 @@ # Intel 82575 1G NIC driver module # IGB_OBJS = igb_buf.o igb_debug.o igb_gld.o igb_log.o igb_main.o \ - igb_rx.o igb_stat.o igb_tx.o igb_osdep.o + igb_rx.o igb_stat.o igb_tx.o igb_osdep.o igb_sensor.o # # Intel Pro/100 NIC driver module
--- a/usr/src/uts/common/io/e1000api/e1000_defines.h Tue May 05 22:21:07 2020 -0700 +++ b/usr/src/uts/common/io/e1000api/e1000_defines.h Fri Jun 05 09:22:48 2020 -0700 @@ -252,6 +252,7 @@ #define E1000_SWFW_CSR_SM 0x08 #define E1000_SWFW_PHY2_SM 0x20 #define E1000_SWFW_PHY3_SM 0x40 +#define E1000_SWFW_PWRTS_SM 0x80 #define E1000_SWFW_SW_MNG_SM 0x400 /* Device Control */
--- a/usr/src/uts/common/io/igb/igb_main.c Tue May 05 22:21:07 2020 -0700 +++ b/usr/src/uts/common/io/igb/igb_main.c Fri Jun 05 09:22:48 2020 -0700 @@ -579,6 +579,12 @@ igb->attach_progress |= ATTACH_PROGRESS_INIT_ADAPTER; /* + * Initialize sensors. This swallows any errors to ensure that access to + * the network is still available. + */ + igb_init_sensors(igb); + + /* * Initialize statistics */ if (igb_init_stats(igb) != IGB_SUCCESS) { @@ -831,6 +837,11 @@ } /* + * Clean up sensors + */ + igb_fini_sensors(igb); + + /* * Free multicast table */ igb_release_multicast(igb);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/io/igb/igb_sensor.c Fri Jun 05 09:22:48 2020 -0700 @@ -0,0 +1,222 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2020 Oxide Computer Company + */ + +/* + * Handle and report sensors found on some igb parts. + * + * The Intel I350 has a built-in thermal sensor diode and an optional External + * Thermal Sensor configuration. This external configuration is provided through + * an optional space in the NVM and allows for up to 4 external sensors to be + * defined. Currently, the only defined external thermal sensor is the Microchip + * EMC 1413. As of this time, we haven't encountered a device that uses the EMC + * 1413 in the wild, so while the definitions here are present, that is stubbed + * out for the time. + * + * When accessing the internal sensor, the I350 Datasheet requires that we take + * software/firmware semaphore before proceeding. + */ + +#include "igb_sw.h" +#include <sys/sensors.h> +#include <sys/bitmap.h> + +/* + * Thermal register values. + */ +#define E1000_THMJT_TEMP(x) BITX(x, 8, 0) +#define E1000_THMJT_VALID(x) BITX(x, 31, 31) +#define E1000_THMJT_RESOLUTION 1 +#define E1000_THMJT_PRECISION 5 + +/* + * Misc. definitions required for accessing the NVM space. + */ +#define IGB_NVM_ETS_CFG 0x3e +#define IGB_NVM_ETS_CFG_NSENSORS(x) BITX(x, 2, 0) +#define IGB_NVM_ETS_CFG_TYPE(x) BITX(x, 5, 3) +#define IGB_NVM_ETS_CFG_TYPE_EMC1413 0 + +#define IGB_NVM_ETS_SENSOR_LOC(x) BITX(x, 13, 10) +#define IGB_NVM_ETS_SENSOR_INDEX(x) BITX(x, 9, 8) +#define IGB_NVM_ETS_SENSOR_THRESH(x) BITX(x, 7, 0) + +#define IGB_ETS_I2C_ADDRESS 0xf8 + +/* + * These definitions come from the Microchip datasheet for the thermal diode + * sensor defined by the external spec. These parts have an accuracy of 1 degree + * and a granularity of 1/8th of a degree. + */ +#define EMC1413_REG_CFG 0x03 +#define EMC1413_REG_CFG_RANGE (1 << 2) +#define EMC1413_RANGE_ADJ (-64) +#define EMC1413_REG_INT_DIODE_HI 0x00 +#define EMC1413_REG_INT_DIODE_LO 0x29 +#define EMC1413_REG_EXT1_DIODE_HI 0x01 +#define EMC1413_REG_EXT1_DIODE_LO 0x10 +#define EMC1413_REG_EXT2_DIODE_HI 0x23 +#define EMC1413_REG_EXT2_DIODE_LO 0x24 +#define EMC1413_REG_EXT3_DIODE_HI 0x2a +#define EMC1413_REG_EXT3_DIODE_LO 0x2b + +static int +igb_sensor_reg_temp(void *arg, sensor_ioctl_temperature_t *temp) +{ + igb_t *igb = arg; + uint32_t reg; + + if (igb->hw.mac.ops.acquire_swfw_sync(&igb->hw, E1000_SWFW_PWRTS_SM) != + E1000_SUCCESS) { + return (EIO); + } + reg = E1000_READ_REG(&igb->hw, E1000_THMJT); + igb->hw.mac.ops.release_swfw_sync(&igb->hw, E1000_SWFW_PWRTS_SM); + if (E1000_THMJT_VALID(reg) == 0) { + return (EIO); + } + + temp->sit_unit = SENSOR_UNIT_CELSIUS; + temp->sit_gran = E1000_THMJT_RESOLUTION; + temp->sit_prec = E1000_THMJT_PRECISION; + temp->sit_temp = E1000_THMJT_TEMP(reg); + + return (0); +} + +static const ksensor_ops_t igb_sensor_reg_ops = { + .kso_kind = ksensor_kind_temperature, + .kso_temp = igb_sensor_reg_temp +}; + +static boolean_t +igb_sensors_create_minors(igb_t *igb) +{ + int ret; + igb_sensors_t *sp = &igb->igb_sensors; + + if ((ret = ksensor_create_temp_pcidev(igb->dip, &igb_sensor_reg_ops, + igb, "builtin", &sp->isn_reg_ksensor)) != 0) { + igb_log(igb, IGB_LOG_ERROR, "failed to create main sensor: %d", + ret); + return (B_FALSE); + } + + return (B_TRUE); +} + +static boolean_t +igb_sensors_init_ets(igb_t *igb, uint_t ets_off, uint_t index) +{ + uint16_t val; + int ret; + igb_sensors_t *sensors = &igb->igb_sensors; + igb_ets_t *etsp = &sensors->isn_ets[sensors->isn_nents]; + igb_ets_loc_t loc; + + if ((ret = e1000_read_nvm(&igb->hw, ets_off, 1, &val)) != + E1000_SUCCESS) { + igb_log(igb, IGB_LOG_ERROR, "failed to read ETS word " + "at offset 0x%x: error %d", ets_off, ret); + return (B_FALSE); + } + + /* + * The data sheet says that if the location is listed as N/A, then we + * should not display this sensor. In this case, we just skip it. + */ + loc = IGB_NVM_ETS_SENSOR_LOC(val); + if (loc == IGB_ETS_LOC_NA) { + return (B_TRUE); + } + + etsp->iet_loc = loc; + etsp->iet_index = IGB_NVM_ETS_SENSOR_INDEX(val); + etsp->iet_thresh = IGB_NVM_ETS_SENSOR_THRESH(val); + sensors->isn_nents++; + + return (B_TRUE); +} + +void +igb_init_sensors(igb_t *igb) +{ + struct e1000_hw *hw = &igb->hw; + uint16_t ets_off; + + /* + * Only the I350 supports the thermal temperature sensor values. This is + * device-wide, so only enumerate on bus zero. + */ + hw = &igb->hw; + if (hw->mac.type != e1000_i350 || hw->bus.func != 0) { + return; + } + + ets_off = 0xffff; + (void) e1000_read_nvm(hw, IGB_NVM_ETS_CFG, 1, &ets_off); + if (ets_off != 0 && ets_off != 0xffff) { + int ret; + uint_t nents, i; + uint16_t val; + + /* + * Swallow the fact that we can't read the ETS config. + */ + if ((ret = e1000_read_nvm(hw, ets_off, 1, &val)) != + E1000_SUCCESS) { + igb_log(igb, IGB_LOG_ERROR, "failed to read ETS word " + "at offset 0x%x: error %d", ets_off, ret); + return; + } + + /* + * If we don't find this, assume we can't use the external + * sensor either. + */ + if (IGB_NVM_ETS_CFG_TYPE(val) != IGB_NVM_ETS_CFG_TYPE_EMC1413) { + return; + } + + nents = IGB_NVM_ETS_CFG_NSENSORS(val); + if (nents > IGB_ETS_MAX) { + igb_log(igb, IGB_LOG_ERROR, "firmware NVM ETS " + "configuration has more entries (%d) than allowed", + nents); + nents = IGB_ETS_MAX; + } + + for (i = 0; i < nents; i++) { + if (!igb_sensors_init_ets(igb, ets_off, i)) { + return; + } + } + } + + if (!igb_sensors_create_minors(igb)) { + (void) ksensor_remove(igb->dip, KSENSOR_ALL_IDS); + return; + } + + igb->igb_sensors.isn_valid = B_TRUE; +} + +void +igb_fini_sensors(igb_t *igb) +{ + if (igb->igb_sensors.isn_valid) { + (void) ksensor_remove(igb->dip, KSENSOR_ALL_IDS); + igb->igb_sensors.isn_valid = B_FALSE; + } +}
--- a/usr/src/uts/common/io/igb/igb_sw.h Tue May 05 22:21:07 2020 -0700 +++ b/usr/src/uts/common/io/igb/igb_sw.h Fri Jun 05 09:22:48 2020 -0700 @@ -561,6 +561,44 @@ struct igb *igb; /* Pointer to igb struct */ } igb_rx_group_t; +typedef enum { + IGB_ETS_INDEX_INTERNAL = 0, + IGB_ETS_INDEX_EXTERNAL_1 = 1, + IGB_ETS_INDEX_EXTERNAL_2 = 2, + IGB_ETS_INDEX_EXTERNAL_3 = 3 +} igb_ets_index_t; + +typedef enum { + IGB_ETS_LOC_NA = 0, + IGB_ETS_LOC_HOT_SPOT = 2, + IGB_ETS_LOC_PCIE = 3, + IGB_ETS_LOC_BULKHEAD = 4, + IGB_ETS_LOC_BOARD = 5, + IGB_ETS_LOC_INLET = 7 +} igb_ets_loc_t; + +/* + * Sensor data + */ +typedef struct igb_ets { + igb_ets_index_t iet_index; + igb_ets_loc_t iet_loc; + uint8_t iet_thresh; + id_t iet_ksensor; +} igb_ets_t; + +/* + * There are only four words defined for sensors. + */ +#define IGB_ETS_MAX 4 + +typedef struct igb_sensors { + boolean_t isn_valid; + id_t isn_reg_ksensor; + uint_t isn_nents; + igb_ets_t isn_ets[IGB_ETS_MAX]; +} igb_sensors_t; + typedef struct igb { int instance; mac_handle_t mac_hdl; @@ -737,6 +775,7 @@ ulong_t page_size; ddi_ufm_handle_t *igb_ufmh; + igb_sensors_t igb_sensors; } igb_t; typedef struct igb_stat { @@ -876,6 +915,12 @@ int igb_rx_ring_stat(mac_ring_driver_t, uint_t, uint64_t *); int igb_tx_ring_stat(mac_ring_driver_t, uint_t, uint64_t *); +/* + * Function prootypes in igb_sesnor.c + */ +void igb_init_sensors(igb_t *); +void igb_fini_sensors(igb_t *); + #ifdef __cplusplus } #endif
--- a/usr/src/uts/intel/igb/Makefile Tue May 05 22:21:07 2020 -0700 +++ b/usr/src/uts/intel/igb/Makefile Fri Jun 05 09:22:48 2020 -0700 @@ -69,7 +69,7 @@ # Driver depends on MAC # LDFLAGS += -dy -N misc/mac -MAPFILES += ddi mac random kernel +MAPFILES += ddi mac random kernel ksensor # # Default build targets.