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