1 /* Copyright 2013-2015 IBM Corp.
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *	http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12  * implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <xscom.h>
18 #include <chip.h>
19 #include <sensor.h>
20 #include <dts.h>
21 #include <skiboot.h>
22 #include <opal-api.h>
23 #include <opal-msg.h>
24 #include <timer.h>
25 #include <timebase.h>
26 
27 struct dts {
28 	uint8_t		valid;
29 	uint8_t		trip;
30 	int16_t		temp;
31 };
32 
33 /*
34  * Attributes for the core temperature sensor
35  */
36 enum {
37 	SENSOR_DTS_ATTR_TEMP_MAX,
38 	SENSOR_DTS_ATTR_TEMP_TRIP
39 };
40 
41 
42 /* Therm mac result masking for DTS (result(0:15)
43  *  0:3   - 0x0
44  *  4:11  - Temperature in degrees C
45  *  12:13 - trip bits: 00 - no trip; 01 - warning; 10 - critical; 11 - fatal
46  *  14    - spare
47  *  15    - valid
48  */
dts_decode_one_dts(uint16_t raw,struct dts * dts)49 static void dts_decode_one_dts(uint16_t raw, struct dts *dts)
50 {
51 	/*
52 	 * The value is both signed and unsigned :-) 0xff could be
53 	 * either 255C or -1C, so for now we treat this as unsigned
54 	 * which is sufficient for our purpose. We could try to be
55 	 * a bit smarter and treat it as signed for values between
56 	 * -10 and 0 and unsigned to 239 or something like that...
57 	 */
58 	dts->valid = raw & 1;
59 	if (dts->valid) {
60 		dts->temp = (raw >> 4) & 0xff;
61 		dts->trip = (raw >> 2) & 0x3;
62 	} else {
63 		dts->temp = 0;
64 		dts->trip = 0;
65 	}
66 }
67 
dts_keep_max(struct dts * temps,int n,struct dts * dts)68 static void dts_keep_max(struct dts *temps, int n, struct dts *dts)
69 {
70 	int i;
71 
72 	for (i = 0; i < n; i++) {
73 		int16_t t = temps[i].temp;
74 
75 		if (!temps[i].valid)
76 			continue;
77 
78 		if (t > dts->temp)
79 			dts->temp = t;
80 
81 		dts->valid++;
82 		dts->trip |= temps[i].trip;
83 	}
84 }
85 
86 /* Per core Digital Thermal Sensors */
87 #define EX_THERM_DTS_RESULT0	0x10050000
88 #define EX_THERM_DTS_RESULT1	0x10050001
89 
90 /* Different sensor locations */
91 #define P8_CT_ZONE_LSU	0
92 #define P8_CT_ZONE_ISU	1
93 #define P8_CT_ZONE_FXU	2
94 #define P8_CT_ZONE_L3C	3
95 #define P8_CT_ZONES	4
96 
97 /*
98  * Returns the temperature as the max of all 4 zones and a global trip
99  * attribute.
100  */
dts_read_core_temp_p8(uint32_t pir,struct dts * dts)101 static int dts_read_core_temp_p8(uint32_t pir, struct dts *dts)
102 {
103 	int32_t chip_id = pir_to_chip_id(pir);
104 	int32_t core = pir_to_core_id(pir);
105 	uint64_t dts0, dts1;
106 	struct dts temps[P8_CT_ZONES];
107 	int rc;
108 
109 	rc = xscom_read(chip_id, XSCOM_ADDR_P8_EX(core, EX_THERM_DTS_RESULT0),
110 			&dts0);
111 	if (rc)
112 		return rc;
113 
114 	rc = xscom_read(chip_id, XSCOM_ADDR_P8_EX(core, EX_THERM_DTS_RESULT1),
115 			&dts1);
116 	if (rc)
117 		return rc;
118 
119 	dts_decode_one_dts(dts0 >> 48, &temps[P8_CT_ZONE_LSU]);
120 	dts_decode_one_dts(dts0 >> 32, &temps[P8_CT_ZONE_ISU]);
121 	dts_decode_one_dts(dts0 >> 16, &temps[P8_CT_ZONE_FXU]);
122 	dts_decode_one_dts(dts1 >> 48, &temps[P8_CT_ZONE_L3C]);
123 
124 	dts_keep_max(temps, P8_CT_ZONES, dts);
125 
126 	prlog(PR_TRACE, "DTS: Chip %x Core %x temp:%dC trip:%x\n",
127 	      chip_id, core, dts->temp, dts->trip);
128 
129 	/*
130 	 * FIXME: The trip bits are always set ?! Just discard
131 	 * them for the moment until we understand why.
132 	 */
133 	dts->trip = 0;
134 	return 0;
135 }
136 
137 /* Per core Digital Thermal Sensors */
138 #define EC_THERM_P9_DTS_RESULT0	0x050000
139 
140 /* Different sensor locations */
141 #define P9_CORE_DTS0	0
142 #define P9_CORE_DTS1	1
143 #define P9_CORE_ZONES	2
144 
145 /*
146  * Returns the temperature as the max of all zones and a global trip
147  * attribute.
148  */
dts_read_core_temp_p9(uint32_t pir,struct dts * dts)149 static int dts_read_core_temp_p9(uint32_t pir, struct dts *dts)
150 {
151 	int32_t chip_id = pir_to_chip_id(pir);
152 	int32_t core = pir_to_core_id(pir);
153 	uint64_t dts0;
154 	struct dts temps[P9_CORE_ZONES];
155 	int rc;
156 
157 	rc = xscom_read(chip_id, XSCOM_ADDR_P9_EC(core, EC_THERM_P9_DTS_RESULT0),
158 			&dts0);
159 	if (rc)
160 		return rc;
161 
162 	dts_decode_one_dts(dts0 >> 48, &temps[P9_CORE_DTS0]);
163 	dts_decode_one_dts(dts0 >> 32, &temps[P9_CORE_DTS1]);
164 
165 	dts_keep_max(temps, P9_CORE_ZONES, dts);
166 
167 	prlog(PR_TRACE, "DTS: Chip %x Core %x temp:%dC trip:%x\n",
168 	      chip_id, core, dts->temp, dts->trip);
169 
170 	/*
171 	 * FIXME: The trip bits are always set ?! Just discard
172 	 * them for the moment until we understand why.
173 	 */
174 	dts->trip = 0;
175 	return 0;
176 }
177 
dts_async_read_temp(struct timer * t __unused,void * data,u64 now __unused)178 static void dts_async_read_temp(struct timer *t __unused, void *data,
179 				u64 now __unused)
180 {
181 	struct dts dts = {0};
182 	int rc, swkup_rc;
183 	struct cpu_thread *cpu = data;
184 
185 	swkup_rc = dctl_set_special_wakeup(cpu);
186 
187 	rc = dts_read_core_temp_p9(cpu->pir, &dts);
188 	if (!rc) {
189 		if (cpu->sensor_attr == SENSOR_DTS_ATTR_TEMP_MAX)
190 			*cpu->sensor_data = dts.temp;
191 		else if (cpu->sensor_attr == SENSOR_DTS_ATTR_TEMP_TRIP)
192 			*cpu->sensor_data = dts.trip;
193 	}
194 
195 	if (!swkup_rc)
196 		dctl_clear_special_wakeup(cpu);
197 
198 	check_sensor_read(cpu->token);
199 	rc = opal_queue_msg(OPAL_MSG_ASYNC_COMP, NULL, NULL, cpu->token, rc);
200 	if (rc)
201 		prerror("Failed to queue async message\n");
202 
203 	cpu->dts_read_in_progress = false;
204 }
205 
dts_read_core_temp(u32 pir,struct dts * dts,u8 attr,int token,u64 * sensor_data)206 static int dts_read_core_temp(u32 pir, struct dts *dts, u8 attr,
207 			      int token, u64 *sensor_data)
208 {
209 	struct cpu_thread *cpu;
210 	int rc;
211 
212 	switch (proc_gen) {
213 	case proc_gen_p8:
214 		rc = dts_read_core_temp_p8(pir, dts);
215 		break;
216 	case proc_gen_p9: /* Asynchronus read */
217 		cpu = find_cpu_by_pir(pir);
218 		if (!cpu)
219 			return OPAL_PARAMETER;
220 		lock(&cpu->dts_lock);
221 		if (cpu->dts_read_in_progress) {
222 			unlock(&cpu->dts_lock);
223 			return OPAL_BUSY;
224 		}
225 		cpu->dts_read_in_progress = true;
226 		cpu->sensor_attr = attr;
227 		cpu->sensor_data = sensor_data;
228 		cpu->token = token;
229 		schedule_timer(&cpu->dts_timer, 0);
230 		rc = OPAL_ASYNC_COMPLETION;
231 		unlock(&cpu->dts_lock);
232 		break;
233 	default:
234 		rc = OPAL_UNSUPPORTED;
235 	}
236 	return rc;
237 }
238 
239 /* Per memory controller Digital Thermal Sensors */
240 #define THERM_MEM_DTS_RESULT0	0x2050000
241 
242 /* Different sensor locations */
243 #define P8_MEM_DTS0	0
244 #define P8_MEM_DTS1	1
245 #define P8_MEM_ZONES	2
246 
dts_read_mem_temp(uint32_t chip_id,struct dts * dts)247 static int dts_read_mem_temp(uint32_t chip_id, struct dts *dts)
248 {
249 	uint64_t dts0;
250 	struct dts temps[P8_MEM_ZONES];
251 	int i;
252 	int rc;
253 
254 	rc = xscom_read(chip_id, THERM_MEM_DTS_RESULT0, &dts0);
255 	if (rc)
256 		return rc;
257 
258 	dts_decode_one_dts(dts0 >> 48, &temps[P8_MEM_DTS0]);
259 	dts_decode_one_dts(dts0 >> 32, &temps[P8_MEM_DTS1]);
260 
261 	for (i = 0; i < P8_MEM_ZONES; i++) {
262 		int16_t t = temps[i].temp;
263 
264 		if (!temps[i].valid)
265 			continue;
266 
267 		/* keep the max temperature of all 4 sensors */
268 		if (t > dts->temp)
269 			dts->temp = t;
270 
271 		dts->valid++;
272 		dts->trip |= temps[i].trip;
273 	}
274 
275 	prlog(PR_TRACE, "DTS: Chip %x temp:%dC trip:%x\n",
276 	      chip_id, dts->temp, dts->trip);
277 
278 	/*
279 	 * FIXME: The trip bits are always set ?! Just discard
280 	 * them for the moment until we understand why.
281 	 */
282 	dts->trip = 0;
283 	return 0;
284 }
285 
286 /*
287  * DTS sensor class ids. Only one for the moment: the core
288  * temperature.
289  */
290 enum sensor_dts_class {
291 	SENSOR_DTS_CORE_TEMP,
292 	SENSOR_DTS_MEM_TEMP,
293 	/* To be continued */
294 };
295 
296 /*
297  * Extract the centaur chip id which was truncated to fit in the
298  * resource identifier field of the sensor handler
299  */
300 #define centaur_get_id(rid) (0x80000000 | ((rid) & 0x3ff))
301 
dts_sensor_read(u32 sensor_hndl,int token,u64 * sensor_data)302 int64_t dts_sensor_read(u32 sensor_hndl, int token, u64 *sensor_data)
303 {
304 	uint8_t	attr = sensor_get_attr(sensor_hndl);
305 	uint32_t rid = sensor_get_rid(sensor_hndl);
306 	struct dts dts = {0};
307 	int64_t rc;
308 
309 	if (attr > SENSOR_DTS_ATTR_TEMP_TRIP)
310 		return OPAL_PARAMETER;
311 
312 	memset(&dts, 0, sizeof(struct dts));
313 
314 	switch (sensor_get_frc(sensor_hndl)) {
315 	case SENSOR_DTS_CORE_TEMP:
316 		rc = dts_read_core_temp(rid, &dts, attr, token, sensor_data);
317 		break;
318 	case SENSOR_DTS_MEM_TEMP:
319 		rc = dts_read_mem_temp(centaur_get_id(rid), &dts);
320 		break;
321 	default:
322 		rc = OPAL_PARAMETER;
323 		break;
324 	}
325 	if (rc)
326 		return rc;
327 
328 	if (attr == SENSOR_DTS_ATTR_TEMP_MAX)
329 		*sensor_data = dts.temp;
330 	else if (attr == SENSOR_DTS_ATTR_TEMP_TRIP)
331 		*sensor_data = dts.trip;
332 
333 	return 0;
334 }
335 
336 /*
337  * We only have two bytes for the resource identifier in the sensor
338  * handler. Let's trunctate the centaur chip id to squeeze it in.
339  *
340  * Centaur chip IDs are using the XSCOM "partID" encoding described in
341  * xscom.h. recap:
342  *
343  *     0b1000.0000.0000.0000.0000.00NN.NCCC.MMMM
344  *     N=Node, C=Chip, M=Memory Channel
345  */
346 #define centaur_make_id(cen_id, dimm_id)	\
347 	(((chip_id) & 0x3ff) | ((dimm_id) << 10))
348 
349 #define core_handler(core_id, attr_id)					\
350 	sensor_make_handler(SENSOR_DTS, SENSOR_DTS_CORE_TEMP,		\
351 			    core_id, attr_id)
352 
353 #define cen_handler(cen_id, attr_id)					\
354 	sensor_make_handler(SENSOR_DTS, SENSOR_DTS_MEM_TEMP,		\
355 			    centaur_make_id(chip_id, 0), attr_id)
356 
dts_sensor_create_nodes(struct dt_node * sensors)357 bool dts_sensor_create_nodes(struct dt_node *sensors)
358 {
359 	struct proc_chip *chip;
360 	struct dt_node *cn;
361 	char name[64];
362 
363 	/* build the device tree nodes :
364 	 *
365 	 *     sensors/core-temp@pir
366 	 *
367 	 * The core is identified by its PIR, is stored in the resource
368 	 * number of the sensor handler.
369 	 */
370 	for_each_chip(chip) {
371 		struct cpu_thread *c;
372 
373 		for_each_available_core_in_chip(c, chip->id) {
374 			struct dt_node *node;
375 			uint32_t handler;
376 
377 			snprintf(name, sizeof(name), "core-temp@%x", c->pir);
378 
379 			handler = core_handler(c->pir, SENSOR_DTS_ATTR_TEMP_MAX);
380 			node = dt_new(sensors, name);
381 			dt_add_property_string(node, "compatible",
382 					       "ibm,opal-sensor");
383 			dt_add_property_cells(node, "sensor-data", handler);
384 			handler = core_handler(c->pir, SENSOR_DTS_ATTR_TEMP_TRIP);
385 			dt_add_property_cells(node, "sensor-status", handler);
386 			dt_add_property_string(node, "sensor-type", "temp");
387 			dt_add_property_cells(node, "ibm,pir", c->pir);
388 			dt_add_property_cells(node, "reg", handler);
389 			dt_add_property_string(node, "label", "Core");
390 			init_timer(&c->dts_timer, dts_async_read_temp, c);
391 			c->dts_read_in_progress = false;
392 		}
393 	}
394 
395 	/*
396 	 * sensors/mem-temp@chip for Centaurs
397 	 */
398 	dt_for_each_compatible(dt_root, cn, "ibm,centaur") {
399 		uint32_t chip_id;
400 		struct dt_node *node;
401 		uint32_t handler;
402 
403 		chip_id = dt_prop_get_u32(cn, "ibm,chip-id");
404 
405 		snprintf(name, sizeof(name), "mem-temp@%x", chip_id);
406 
407 		handler = cen_handler(chip_id, SENSOR_DTS_ATTR_TEMP_MAX);
408 		node = dt_new(sensors, name);
409 		dt_add_property_string(node, "compatible",
410 				       "ibm,opal-sensor");
411 		dt_add_property_cells(node, "sensor-data", handler);
412 
413 		handler = cen_handler(chip_id, SENSOR_DTS_ATTR_TEMP_TRIP);
414 		dt_add_property_cells(node, "sensor-status", handler);
415 		dt_add_property_string(node, "sensor-type", "temp");
416 		dt_add_property_cells(node, "ibm,chip-id", chip_id);
417 		dt_add_property_cells(node, "reg", handler);
418 		dt_add_property_string(node, "label", "Centaur");
419 	}
420 
421 	return true;
422 }
423