1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2020 Oxide Computer Company
14 */
15
16 /*
17 * Handle and report sensors found on some igb parts.
18 *
19 * The Intel I350 has a built-in thermal sensor diode and an optional External
20 * Thermal Sensor configuration. This external configuration is provided through
21 * an optional space in the NVM and allows for up to 4 external sensors to be
22 * defined. Currently, the only defined external thermal sensor is the Microchip
23 * EMC 1413. As of this time, we haven't encountered a device that uses the EMC
24 * 1413 in the wild, so while the definitions here are present, that is stubbed
25 * out for the time.
26 *
27 * When accessing the internal sensor, the I350 Datasheet requires that we take
28 * software/firmware semaphore before proceeding.
29 */
30
31 #include "igb_sw.h"
32 #include <sys/sensors.h>
33 #include <sys/bitmap.h>
34
35 /*
36 * Thermal register values.
37 */
38 #define E1000_THMJT_TEMP(x) BITX(x, 8, 0)
39 #define E1000_THMJT_VALID(x) BITX(x, 31, 31)
40 #define E1000_THMJT_RESOLUTION 1
41 #define E1000_THMJT_PRECISION 5
42
43 /*
44 * Misc. definitions required for accessing the NVM space.
45 */
46 #define IGB_NVM_ETS_CFG 0x3e
47 #define IGB_NVM_ETS_CFG_NSENSORS(x) BITX(x, 2, 0)
48 #define IGB_NVM_ETS_CFG_TYPE(x) BITX(x, 5, 3)
49 #define IGB_NVM_ETS_CFG_TYPE_EMC1413 0
50
51 #define IGB_NVM_ETS_SENSOR_LOC(x) BITX(x, 13, 10)
52 #define IGB_NVM_ETS_SENSOR_INDEX(x) BITX(x, 9, 8)
53 #define IGB_NVM_ETS_SENSOR_THRESH(x) BITX(x, 7, 0)
54
55 #define IGB_ETS_I2C_ADDRESS 0xf8
56
57 /*
58 * These definitions come from the Microchip datasheet for the thermal diode
59 * sensor defined by the external spec. These parts have an accuracy of 1 degree
60 * and a granularity of 1/8th of a degree.
61 */
62 #define EMC1413_REG_CFG 0x03
63 #define EMC1413_REG_CFG_RANGE (1 << 2)
64 #define EMC1413_RANGE_ADJ (-64)
65 #define EMC1413_REG_INT_DIODE_HI 0x00
66 #define EMC1413_REG_INT_DIODE_LO 0x29
67 #define EMC1413_REG_EXT1_DIODE_HI 0x01
68 #define EMC1413_REG_EXT1_DIODE_LO 0x10
69 #define EMC1413_REG_EXT2_DIODE_HI 0x23
70 #define EMC1413_REG_EXT2_DIODE_LO 0x24
71 #define EMC1413_REG_EXT3_DIODE_HI 0x2a
72 #define EMC1413_REG_EXT3_DIODE_LO 0x2b
73
74 static int
igb_sensor_reg_temperature(void * arg,sensor_ioctl_scalar_t * scalar)75 igb_sensor_reg_temperature(void *arg, sensor_ioctl_scalar_t *scalar)
76 {
77 igb_t *igb = arg;
78 uint32_t reg;
79
80 if (igb->hw.mac.ops.acquire_swfw_sync(&igb->hw, E1000_SWFW_PWRTS_SM) !=
81 E1000_SUCCESS) {
82 return (EIO);
83 }
84 reg = E1000_READ_REG(&igb->hw, E1000_THMJT);
85 igb->hw.mac.ops.release_swfw_sync(&igb->hw, E1000_SWFW_PWRTS_SM);
86 if (E1000_THMJT_VALID(reg) == 0) {
87 return (EIO);
88 }
89
90 scalar->sis_unit = SENSOR_UNIT_CELSIUS;
91 scalar->sis_gran = E1000_THMJT_RESOLUTION;
92 scalar->sis_prec = E1000_THMJT_PRECISION;
93 scalar->sis_value = E1000_THMJT_TEMP(reg);
94
95 return (0);
96 }
97
98 static const ksensor_ops_t igb_sensor_reg_ops = {
99 .kso_kind = ksensor_kind_temperature,
100 .kso_scalar = igb_sensor_reg_temperature
101 };
102
103 static boolean_t
igb_sensors_create_minors(igb_t * igb)104 igb_sensors_create_minors(igb_t *igb)
105 {
106 int ret;
107 igb_sensors_t *sp = &igb->igb_sensors;
108
109 if ((ret = ksensor_create_scalar_pcidev(igb->dip,
110 SENSOR_KIND_TEMPERATURE, &igb_sensor_reg_ops, igb, "builtin",
111 &sp->isn_reg_ksensor)) != 0) {
112 igb_log(igb, IGB_LOG_ERROR, "failed to create main sensor: %d",
113 ret);
114 return (B_FALSE);
115 }
116
117 return (B_TRUE);
118 }
119
120 static boolean_t
igb_sensors_init_ets(igb_t * igb,uint_t ets_off,uint_t index)121 igb_sensors_init_ets(igb_t *igb, uint_t ets_off, uint_t index)
122 {
123 uint16_t val;
124 int ret;
125 igb_sensors_t *sensors = &igb->igb_sensors;
126 igb_ets_t *etsp = &sensors->isn_ets[sensors->isn_nents];
127 igb_ets_loc_t loc;
128
129 if ((ret = e1000_read_nvm(&igb->hw, ets_off, 1, &val)) !=
130 E1000_SUCCESS) {
131 igb_log(igb, IGB_LOG_ERROR, "failed to read ETS word "
132 "at offset 0x%x: error %d", ets_off, ret);
133 return (B_FALSE);
134 }
135
136 /*
137 * The data sheet says that if the location is listed as N/A, then we
138 * should not display this sensor. In this case, we just skip it.
139 */
140 loc = IGB_NVM_ETS_SENSOR_LOC(val);
141 if (loc == IGB_ETS_LOC_NA) {
142 return (B_TRUE);
143 }
144
145 etsp->iet_loc = loc;
146 etsp->iet_index = IGB_NVM_ETS_SENSOR_INDEX(val);
147 etsp->iet_thresh = IGB_NVM_ETS_SENSOR_THRESH(val);
148 sensors->isn_nents++;
149
150 return (B_TRUE);
151 }
152
153 void
igb_init_sensors(igb_t * igb)154 igb_init_sensors(igb_t *igb)
155 {
156 struct e1000_hw *hw = &igb->hw;
157 uint16_t ets_off;
158
159 /*
160 * Only the I350 supports the thermal temperature sensor values. This is
161 * device-wide, so only enumerate on bus zero.
162 */
163 hw = &igb->hw;
164 if (hw->mac.type != e1000_i350 || hw->bus.func != 0) {
165 return;
166 }
167
168 ets_off = 0xffff;
169 (void) e1000_read_nvm(hw, IGB_NVM_ETS_CFG, 1, &ets_off);
170 if (ets_off != 0 && ets_off != 0xffff) {
171 int ret;
172 uint_t nents, i;
173 uint16_t val;
174
175 /*
176 * Swallow the fact that we can't read the ETS config.
177 */
178 if ((ret = e1000_read_nvm(hw, ets_off, 1, &val)) !=
179 E1000_SUCCESS) {
180 igb_log(igb, IGB_LOG_ERROR, "failed to read ETS word "
181 "at offset 0x%x: error %d", ets_off, ret);
182 return;
183 }
184
185 /*
186 * If we don't find this, assume we can't use the external
187 * sensor either.
188 */
189 if (IGB_NVM_ETS_CFG_TYPE(val) != IGB_NVM_ETS_CFG_TYPE_EMC1413) {
190 return;
191 }
192
193 nents = IGB_NVM_ETS_CFG_NSENSORS(val);
194 if (nents > IGB_ETS_MAX) {
195 igb_log(igb, IGB_LOG_ERROR, "firmware NVM ETS "
196 "configuration has more entries (%d) than allowed",
197 nents);
198 nents = IGB_ETS_MAX;
199 }
200
201 for (i = 0; i < nents; i++) {
202 if (!igb_sensors_init_ets(igb, ets_off, i)) {
203 return;
204 }
205 }
206 }
207
208 if (!igb_sensors_create_minors(igb)) {
209 (void) ksensor_remove(igb->dip, KSENSOR_ALL_IDS);
210 return;
211 }
212
213 igb->igb_sensors.isn_valid = B_TRUE;
214 }
215
216 void
igb_fini_sensors(igb_t * igb)217 igb_fini_sensors(igb_t *igb)
218 {
219 if (igb->igb_sensors.isn_valid) {
220 (void) ksensor_remove(igb->dip, KSENSOR_ALL_IDS);
221 igb->igb_sensors.isn_valid = B_FALSE;
222 }
223 }
224