1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved
3 * Copyright (c) 2016 Ivan Vecera <cera@cera.cz>
4 */
5
6 #include <linux/kernel.h>
7 #include <linux/types.h>
8 #include <linux/device.h>
9 #include <linux/sysfs.h>
10 #include <linux/thermal.h>
11 #include <linux/err.h>
12 #include <linux/sfp.h>
13
14 #include "core.h"
15 #include "core_env.h"
16
17 #define MLXSW_THERMAL_POLL_INT 1000 /* ms */
18 #define MLXSW_THERMAL_SLOW_POLL_INT 20000 /* ms */
19 #define MLXSW_THERMAL_ASIC_TEMP_NORM 75000 /* 75C */
20 #define MLXSW_THERMAL_ASIC_TEMP_HIGH 85000 /* 85C */
21 #define MLXSW_THERMAL_ASIC_TEMP_HOT 105000 /* 105C */
22 #define MLXSW_THERMAL_ASIC_TEMP_CRIT 110000 /* 110C */
23 #define MLXSW_THERMAL_HYSTERESIS_TEMP 5000 /* 5C */
24 #define MLXSW_THERMAL_MODULE_TEMP_SHIFT (MLXSW_THERMAL_HYSTERESIS_TEMP * 2)
25 #define MLXSW_THERMAL_ZONE_MAX_NAME 16
26 #define MLXSW_THERMAL_TEMP_SCORE_MAX GENMASK(31, 0)
27 #define MLXSW_THERMAL_MAX_STATE 10
28 #define MLXSW_THERMAL_MAX_DUTY 255
29 /* Minimum and maximum fan allowed speed in percent: from 20% to 100%. Values
30 * MLXSW_THERMAL_MAX_STATE + x, where x is between 2 and 10 are used for
31 * setting fan speed dynamic minimum. For example, if value is set to 14 (40%)
32 * cooling levels vector will be set to 4, 4, 4, 4, 4, 5, 6, 7, 8, 9, 10 to
33 * introduce PWM speed in percent: 40, 40, 40, 40, 40, 50, 60. 70, 80, 90, 100.
34 */
35 #define MLXSW_THERMAL_SPEED_MIN (MLXSW_THERMAL_MAX_STATE + 2)
36 #define MLXSW_THERMAL_SPEED_MAX (MLXSW_THERMAL_MAX_STATE * 2)
37 #define MLXSW_THERMAL_SPEED_MIN_LEVEL 2 /* 20% */
38
39 /* External cooling devices, allowed for binding to mlxsw thermal zones. */
40 static char * const mlxsw_thermal_external_allowed_cdev[] = {
41 "mlxreg_fan",
42 };
43
44 enum mlxsw_thermal_trips {
45 MLXSW_THERMAL_TEMP_TRIP_NORM,
46 MLXSW_THERMAL_TEMP_TRIP_HIGH,
47 MLXSW_THERMAL_TEMP_TRIP_HOT,
48 MLXSW_THERMAL_TEMP_TRIP_CRIT,
49 };
50
51 struct mlxsw_thermal_trip {
52 int type;
53 int temp;
54 int hyst;
55 int min_state;
56 int max_state;
57 };
58
59 static const struct mlxsw_thermal_trip default_thermal_trips[] = {
60 { /* In range - 0-40% PWM */
61 .type = THERMAL_TRIP_ACTIVE,
62 .temp = MLXSW_THERMAL_ASIC_TEMP_NORM,
63 .hyst = MLXSW_THERMAL_HYSTERESIS_TEMP,
64 .min_state = 0,
65 .max_state = (4 * MLXSW_THERMAL_MAX_STATE) / 10,
66 },
67 {
68 /* In range - 40-100% PWM */
69 .type = THERMAL_TRIP_ACTIVE,
70 .temp = MLXSW_THERMAL_ASIC_TEMP_HIGH,
71 .hyst = MLXSW_THERMAL_HYSTERESIS_TEMP,
72 .min_state = (4 * MLXSW_THERMAL_MAX_STATE) / 10,
73 .max_state = MLXSW_THERMAL_MAX_STATE,
74 },
75 { /* Warning */
76 .type = THERMAL_TRIP_HOT,
77 .temp = MLXSW_THERMAL_ASIC_TEMP_HOT,
78 .hyst = MLXSW_THERMAL_HYSTERESIS_TEMP,
79 .min_state = MLXSW_THERMAL_MAX_STATE,
80 .max_state = MLXSW_THERMAL_MAX_STATE,
81 },
82 { /* Critical - soft poweroff */
83 .type = THERMAL_TRIP_CRITICAL,
84 .temp = MLXSW_THERMAL_ASIC_TEMP_CRIT,
85 .min_state = MLXSW_THERMAL_MAX_STATE,
86 .max_state = MLXSW_THERMAL_MAX_STATE,
87 }
88 };
89
90 #define MLXSW_THERMAL_NUM_TRIPS ARRAY_SIZE(default_thermal_trips)
91
92 /* Make sure all trips are writable */
93 #define MLXSW_THERMAL_TRIP_MASK (BIT(MLXSW_THERMAL_NUM_TRIPS) - 1)
94
95 struct mlxsw_thermal;
96
97 struct mlxsw_thermal_module {
98 struct mlxsw_thermal *parent;
99 struct thermal_zone_device *tzdev;
100 struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
101 int module; /* Module or gearbox number */
102 };
103
104 struct mlxsw_thermal {
105 struct mlxsw_core *core;
106 const struct mlxsw_bus_info *bus_info;
107 struct thermal_zone_device *tzdev;
108 int polling_delay;
109 struct thermal_cooling_device *cdevs[MLXSW_MFCR_PWMS_MAX];
110 u8 cooling_levels[MLXSW_THERMAL_MAX_STATE + 1];
111 struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
112 struct mlxsw_thermal_module *tz_module_arr;
113 u8 tz_module_num;
114 struct mlxsw_thermal_module *tz_gearbox_arr;
115 u8 tz_gearbox_num;
116 unsigned int tz_highest_score;
117 struct thermal_zone_device *tz_highest_dev;
118 };
119
mlxsw_state_to_duty(int state)120 static inline u8 mlxsw_state_to_duty(int state)
121 {
122 return DIV_ROUND_CLOSEST(state * MLXSW_THERMAL_MAX_DUTY,
123 MLXSW_THERMAL_MAX_STATE);
124 }
125
mlxsw_duty_to_state(u8 duty)126 static inline int mlxsw_duty_to_state(u8 duty)
127 {
128 return DIV_ROUND_CLOSEST(duty * MLXSW_THERMAL_MAX_STATE,
129 MLXSW_THERMAL_MAX_DUTY);
130 }
131
mlxsw_get_cooling_device_idx(struct mlxsw_thermal * thermal,struct thermal_cooling_device * cdev)132 static int mlxsw_get_cooling_device_idx(struct mlxsw_thermal *thermal,
133 struct thermal_cooling_device *cdev)
134 {
135 int i;
136
137 for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++)
138 if (thermal->cdevs[i] == cdev)
139 return i;
140
141 /* Allow mlxsw thermal zone binding to an external cooling device */
142 for (i = 0; i < ARRAY_SIZE(mlxsw_thermal_external_allowed_cdev); i++) {
143 if (strnstr(cdev->type, mlxsw_thermal_external_allowed_cdev[i],
144 sizeof(cdev->type)))
145 return 0;
146 }
147
148 return -ENODEV;
149 }
150
151 static void
mlxsw_thermal_module_trips_reset(struct mlxsw_thermal_module * tz)152 mlxsw_thermal_module_trips_reset(struct mlxsw_thermal_module *tz)
153 {
154 tz->trips[MLXSW_THERMAL_TEMP_TRIP_NORM].temp = 0;
155 tz->trips[MLXSW_THERMAL_TEMP_TRIP_HIGH].temp = 0;
156 tz->trips[MLXSW_THERMAL_TEMP_TRIP_HOT].temp = 0;
157 tz->trips[MLXSW_THERMAL_TEMP_TRIP_CRIT].temp = 0;
158 }
159
160 static int
mlxsw_thermal_module_trips_update(struct device * dev,struct mlxsw_core * core,struct mlxsw_thermal_module * tz)161 mlxsw_thermal_module_trips_update(struct device *dev, struct mlxsw_core *core,
162 struct mlxsw_thermal_module *tz)
163 {
164 int crit_temp, emerg_temp;
165 int err;
166
167 err = mlxsw_env_module_temp_thresholds_get(core, tz->module,
168 SFP_TEMP_HIGH_WARN,
169 &crit_temp);
170 if (err)
171 return err;
172
173 err = mlxsw_env_module_temp_thresholds_get(core, tz->module,
174 SFP_TEMP_HIGH_ALARM,
175 &emerg_temp);
176 if (err)
177 return err;
178
179 /* According to the system thermal requirements, the thermal zones are
180 * defined with four trip points. The critical and emergency
181 * temperature thresholds, provided by QSFP module are set as "active"
182 * and "hot" trip points, "normal" and "critical" trip points are
183 * derived from "active" and "hot" by subtracting or adding double
184 * hysteresis value.
185 */
186 if (crit_temp >= MLXSW_THERMAL_MODULE_TEMP_SHIFT)
187 tz->trips[MLXSW_THERMAL_TEMP_TRIP_NORM].temp = crit_temp -
188 MLXSW_THERMAL_MODULE_TEMP_SHIFT;
189 else
190 tz->trips[MLXSW_THERMAL_TEMP_TRIP_NORM].temp = crit_temp;
191 tz->trips[MLXSW_THERMAL_TEMP_TRIP_HIGH].temp = crit_temp;
192 tz->trips[MLXSW_THERMAL_TEMP_TRIP_HOT].temp = emerg_temp;
193 if (emerg_temp > crit_temp)
194 tz->trips[MLXSW_THERMAL_TEMP_TRIP_CRIT].temp = emerg_temp +
195 MLXSW_THERMAL_MODULE_TEMP_SHIFT;
196 else
197 tz->trips[MLXSW_THERMAL_TEMP_TRIP_CRIT].temp = emerg_temp;
198
199 return 0;
200 }
201
mlxsw_thermal_tz_score_update(struct mlxsw_thermal * thermal,struct thermal_zone_device * tzdev,struct mlxsw_thermal_trip * trips,int temp)202 static void mlxsw_thermal_tz_score_update(struct mlxsw_thermal *thermal,
203 struct thermal_zone_device *tzdev,
204 struct mlxsw_thermal_trip *trips,
205 int temp)
206 {
207 struct mlxsw_thermal_trip *trip = trips;
208 unsigned int score, delta, i, shift = 1;
209
210 /* Calculate thermal zone score, if temperature is above the critical
211 * threshold score is set to MLXSW_THERMAL_TEMP_SCORE_MAX.
212 */
213 score = MLXSW_THERMAL_TEMP_SCORE_MAX;
214 for (i = MLXSW_THERMAL_TEMP_TRIP_NORM; i < MLXSW_THERMAL_NUM_TRIPS;
215 i++, trip++) {
216 if (temp < trip->temp) {
217 delta = DIV_ROUND_CLOSEST(temp, trip->temp - temp);
218 score = delta * shift;
219 break;
220 }
221 shift *= 256;
222 }
223
224 if (score > thermal->tz_highest_score) {
225 thermal->tz_highest_score = score;
226 thermal->tz_highest_dev = tzdev;
227 }
228 }
229
mlxsw_thermal_bind(struct thermal_zone_device * tzdev,struct thermal_cooling_device * cdev)230 static int mlxsw_thermal_bind(struct thermal_zone_device *tzdev,
231 struct thermal_cooling_device *cdev)
232 {
233 struct mlxsw_thermal *thermal = tzdev->devdata;
234 struct device *dev = thermal->bus_info->dev;
235 int i, err;
236
237 /* If the cooling device is one of ours bind it */
238 if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0)
239 return 0;
240
241 for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) {
242 const struct mlxsw_thermal_trip *trip = &thermal->trips[i];
243
244 err = thermal_zone_bind_cooling_device(tzdev, i, cdev,
245 trip->max_state,
246 trip->min_state,
247 THERMAL_WEIGHT_DEFAULT);
248 if (err < 0) {
249 dev_err(dev, "Failed to bind cooling device to trip %d\n", i);
250 return err;
251 }
252 }
253 return 0;
254 }
255
mlxsw_thermal_unbind(struct thermal_zone_device * tzdev,struct thermal_cooling_device * cdev)256 static int mlxsw_thermal_unbind(struct thermal_zone_device *tzdev,
257 struct thermal_cooling_device *cdev)
258 {
259 struct mlxsw_thermal *thermal = tzdev->devdata;
260 struct device *dev = thermal->bus_info->dev;
261 int i;
262 int err;
263
264 /* If the cooling device is our one unbind it */
265 if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0)
266 return 0;
267
268 for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) {
269 err = thermal_zone_unbind_cooling_device(tzdev, i, cdev);
270 if (err < 0) {
271 dev_err(dev, "Failed to unbind cooling device\n");
272 return err;
273 }
274 }
275 return 0;
276 }
277
mlxsw_thermal_get_temp(struct thermal_zone_device * tzdev,int * p_temp)278 static int mlxsw_thermal_get_temp(struct thermal_zone_device *tzdev,
279 int *p_temp)
280 {
281 struct mlxsw_thermal *thermal = tzdev->devdata;
282 struct device *dev = thermal->bus_info->dev;
283 char mtmp_pl[MLXSW_REG_MTMP_LEN];
284 int temp;
285 int err;
286
287 mlxsw_reg_mtmp_pack(mtmp_pl, 0, false, false);
288
289 err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl);
290 if (err) {
291 dev_err(dev, "Failed to query temp sensor\n");
292 return err;
293 }
294 mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL);
295 if (temp > 0)
296 mlxsw_thermal_tz_score_update(thermal, tzdev, thermal->trips,
297 temp);
298
299 *p_temp = temp;
300 return 0;
301 }
302
mlxsw_thermal_get_trip_type(struct thermal_zone_device * tzdev,int trip,enum thermal_trip_type * p_type)303 static int mlxsw_thermal_get_trip_type(struct thermal_zone_device *tzdev,
304 int trip,
305 enum thermal_trip_type *p_type)
306 {
307 struct mlxsw_thermal *thermal = tzdev->devdata;
308
309 if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
310 return -EINVAL;
311
312 *p_type = thermal->trips[trip].type;
313 return 0;
314 }
315
mlxsw_thermal_get_trip_temp(struct thermal_zone_device * tzdev,int trip,int * p_temp)316 static int mlxsw_thermal_get_trip_temp(struct thermal_zone_device *tzdev,
317 int trip, int *p_temp)
318 {
319 struct mlxsw_thermal *thermal = tzdev->devdata;
320
321 if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
322 return -EINVAL;
323
324 *p_temp = thermal->trips[trip].temp;
325 return 0;
326 }
327
mlxsw_thermal_set_trip_temp(struct thermal_zone_device * tzdev,int trip,int temp)328 static int mlxsw_thermal_set_trip_temp(struct thermal_zone_device *tzdev,
329 int trip, int temp)
330 {
331 struct mlxsw_thermal *thermal = tzdev->devdata;
332
333 if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS ||
334 temp > MLXSW_THERMAL_ASIC_TEMP_CRIT)
335 return -EINVAL;
336
337 thermal->trips[trip].temp = temp;
338 return 0;
339 }
340
mlxsw_thermal_get_trip_hyst(struct thermal_zone_device * tzdev,int trip,int * p_hyst)341 static int mlxsw_thermal_get_trip_hyst(struct thermal_zone_device *tzdev,
342 int trip, int *p_hyst)
343 {
344 struct mlxsw_thermal *thermal = tzdev->devdata;
345
346 *p_hyst = thermal->trips[trip].hyst;
347 return 0;
348 }
349
mlxsw_thermal_set_trip_hyst(struct thermal_zone_device * tzdev,int trip,int hyst)350 static int mlxsw_thermal_set_trip_hyst(struct thermal_zone_device *tzdev,
351 int trip, int hyst)
352 {
353 struct mlxsw_thermal *thermal = tzdev->devdata;
354
355 thermal->trips[trip].hyst = hyst;
356 return 0;
357 }
358
mlxsw_thermal_trend_get(struct thermal_zone_device * tzdev,int trip,enum thermal_trend * trend)359 static int mlxsw_thermal_trend_get(struct thermal_zone_device *tzdev,
360 int trip, enum thermal_trend *trend)
361 {
362 struct mlxsw_thermal *thermal = tzdev->devdata;
363
364 if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
365 return -EINVAL;
366
367 if (tzdev == thermal->tz_highest_dev)
368 return 1;
369
370 *trend = THERMAL_TREND_STABLE;
371 return 0;
372 }
373
374 static struct thermal_zone_device_ops mlxsw_thermal_ops = {
375 .bind = mlxsw_thermal_bind,
376 .unbind = mlxsw_thermal_unbind,
377 .get_temp = mlxsw_thermal_get_temp,
378 .get_trip_type = mlxsw_thermal_get_trip_type,
379 .get_trip_temp = mlxsw_thermal_get_trip_temp,
380 .set_trip_temp = mlxsw_thermal_set_trip_temp,
381 .get_trip_hyst = mlxsw_thermal_get_trip_hyst,
382 .set_trip_hyst = mlxsw_thermal_set_trip_hyst,
383 .get_trend = mlxsw_thermal_trend_get,
384 };
385
mlxsw_thermal_module_bind(struct thermal_zone_device * tzdev,struct thermal_cooling_device * cdev)386 static int mlxsw_thermal_module_bind(struct thermal_zone_device *tzdev,
387 struct thermal_cooling_device *cdev)
388 {
389 struct mlxsw_thermal_module *tz = tzdev->devdata;
390 struct mlxsw_thermal *thermal = tz->parent;
391 int i, j, err;
392
393 /* If the cooling device is one of ours bind it */
394 if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0)
395 return 0;
396
397 for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) {
398 const struct mlxsw_thermal_trip *trip = &tz->trips[i];
399
400 err = thermal_zone_bind_cooling_device(tzdev, i, cdev,
401 trip->max_state,
402 trip->min_state,
403 THERMAL_WEIGHT_DEFAULT);
404 if (err < 0)
405 goto err_bind_cooling_device;
406 }
407 return 0;
408
409 err_bind_cooling_device:
410 for (j = i - 1; j >= 0; j--)
411 thermal_zone_unbind_cooling_device(tzdev, j, cdev);
412 return err;
413 }
414
mlxsw_thermal_module_unbind(struct thermal_zone_device * tzdev,struct thermal_cooling_device * cdev)415 static int mlxsw_thermal_module_unbind(struct thermal_zone_device *tzdev,
416 struct thermal_cooling_device *cdev)
417 {
418 struct mlxsw_thermal_module *tz = tzdev->devdata;
419 struct mlxsw_thermal *thermal = tz->parent;
420 int i;
421 int err;
422
423 /* If the cooling device is one of ours unbind it */
424 if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0)
425 return 0;
426
427 for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) {
428 err = thermal_zone_unbind_cooling_device(tzdev, i, cdev);
429 WARN_ON(err);
430 }
431 return err;
432 }
433
mlxsw_thermal_module_temp_get(struct thermal_zone_device * tzdev,int * p_temp)434 static int mlxsw_thermal_module_temp_get(struct thermal_zone_device *tzdev,
435 int *p_temp)
436 {
437 struct mlxsw_thermal_module *tz = tzdev->devdata;
438 struct mlxsw_thermal *thermal = tz->parent;
439 struct device *dev = thermal->bus_info->dev;
440 char mtmp_pl[MLXSW_REG_MTMP_LEN];
441 int temp;
442 int err;
443
444 /* Read module temperature. */
445 mlxsw_reg_mtmp_pack(mtmp_pl, MLXSW_REG_MTMP_MODULE_INDEX_MIN +
446 tz->module, false, false);
447 err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl);
448 if (err) {
449 /* Do not return error - in case of broken module's sensor
450 * it will cause error message flooding.
451 */
452 temp = 0;
453 *p_temp = (int) temp;
454 return 0;
455 }
456 mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL);
457 *p_temp = temp;
458
459 if (!temp)
460 return 0;
461
462 /* Update trip points. */
463 err = mlxsw_thermal_module_trips_update(dev, thermal->core, tz);
464 if (!err && temp > 0)
465 mlxsw_thermal_tz_score_update(thermal, tzdev, tz->trips, temp);
466
467 return 0;
468 }
469
470 static int
mlxsw_thermal_module_trip_type_get(struct thermal_zone_device * tzdev,int trip,enum thermal_trip_type * p_type)471 mlxsw_thermal_module_trip_type_get(struct thermal_zone_device *tzdev, int trip,
472 enum thermal_trip_type *p_type)
473 {
474 struct mlxsw_thermal_module *tz = tzdev->devdata;
475
476 if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
477 return -EINVAL;
478
479 *p_type = tz->trips[trip].type;
480 return 0;
481 }
482
483 static int
mlxsw_thermal_module_trip_temp_get(struct thermal_zone_device * tzdev,int trip,int * p_temp)484 mlxsw_thermal_module_trip_temp_get(struct thermal_zone_device *tzdev,
485 int trip, int *p_temp)
486 {
487 struct mlxsw_thermal_module *tz = tzdev->devdata;
488
489 if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
490 return -EINVAL;
491
492 *p_temp = tz->trips[trip].temp;
493 return 0;
494 }
495
496 static int
mlxsw_thermal_module_trip_temp_set(struct thermal_zone_device * tzdev,int trip,int temp)497 mlxsw_thermal_module_trip_temp_set(struct thermal_zone_device *tzdev,
498 int trip, int temp)
499 {
500 struct mlxsw_thermal_module *tz = tzdev->devdata;
501
502 if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS ||
503 temp > tz->trips[MLXSW_THERMAL_TEMP_TRIP_CRIT].temp)
504 return -EINVAL;
505
506 tz->trips[trip].temp = temp;
507 return 0;
508 }
509
510 static int
mlxsw_thermal_module_trip_hyst_get(struct thermal_zone_device * tzdev,int trip,int * p_hyst)511 mlxsw_thermal_module_trip_hyst_get(struct thermal_zone_device *tzdev, int trip,
512 int *p_hyst)
513 {
514 struct mlxsw_thermal_module *tz = tzdev->devdata;
515
516 *p_hyst = tz->trips[trip].hyst;
517 return 0;
518 }
519
520 static int
mlxsw_thermal_module_trip_hyst_set(struct thermal_zone_device * tzdev,int trip,int hyst)521 mlxsw_thermal_module_trip_hyst_set(struct thermal_zone_device *tzdev, int trip,
522 int hyst)
523 {
524 struct mlxsw_thermal_module *tz = tzdev->devdata;
525
526 tz->trips[trip].hyst = hyst;
527 return 0;
528 }
529
mlxsw_thermal_module_trend_get(struct thermal_zone_device * tzdev,int trip,enum thermal_trend * trend)530 static int mlxsw_thermal_module_trend_get(struct thermal_zone_device *tzdev,
531 int trip, enum thermal_trend *trend)
532 {
533 struct mlxsw_thermal_module *tz = tzdev->devdata;
534 struct mlxsw_thermal *thermal = tz->parent;
535
536 if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
537 return -EINVAL;
538
539 if (tzdev == thermal->tz_highest_dev)
540 return 1;
541
542 *trend = THERMAL_TREND_STABLE;
543 return 0;
544 }
545
546 static struct thermal_zone_device_ops mlxsw_thermal_module_ops = {
547 .bind = mlxsw_thermal_module_bind,
548 .unbind = mlxsw_thermal_module_unbind,
549 .get_temp = mlxsw_thermal_module_temp_get,
550 .get_trip_type = mlxsw_thermal_module_trip_type_get,
551 .get_trip_temp = mlxsw_thermal_module_trip_temp_get,
552 .set_trip_temp = mlxsw_thermal_module_trip_temp_set,
553 .get_trip_hyst = mlxsw_thermal_module_trip_hyst_get,
554 .set_trip_hyst = mlxsw_thermal_module_trip_hyst_set,
555 .get_trend = mlxsw_thermal_module_trend_get,
556 };
557
mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device * tzdev,int * p_temp)558 static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev,
559 int *p_temp)
560 {
561 struct mlxsw_thermal_module *tz = tzdev->devdata;
562 struct mlxsw_thermal *thermal = tz->parent;
563 char mtmp_pl[MLXSW_REG_MTMP_LEN];
564 u16 index;
565 int temp;
566 int err;
567
568 index = MLXSW_REG_MTMP_GBOX_INDEX_MIN + tz->module;
569 mlxsw_reg_mtmp_pack(mtmp_pl, index, false, false);
570
571 err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl);
572 if (err)
573 return err;
574
575 mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL);
576 if (temp > 0)
577 mlxsw_thermal_tz_score_update(thermal, tzdev, tz->trips, temp);
578
579 *p_temp = temp;
580 return 0;
581 }
582
583 static struct thermal_zone_device_ops mlxsw_thermal_gearbox_ops = {
584 .bind = mlxsw_thermal_module_bind,
585 .unbind = mlxsw_thermal_module_unbind,
586 .get_temp = mlxsw_thermal_gearbox_temp_get,
587 .get_trip_type = mlxsw_thermal_module_trip_type_get,
588 .get_trip_temp = mlxsw_thermal_module_trip_temp_get,
589 .set_trip_temp = mlxsw_thermal_module_trip_temp_set,
590 .get_trip_hyst = mlxsw_thermal_module_trip_hyst_get,
591 .set_trip_hyst = mlxsw_thermal_module_trip_hyst_set,
592 .get_trend = mlxsw_thermal_module_trend_get,
593 };
594
mlxsw_thermal_get_max_state(struct thermal_cooling_device * cdev,unsigned long * p_state)595 static int mlxsw_thermal_get_max_state(struct thermal_cooling_device *cdev,
596 unsigned long *p_state)
597 {
598 *p_state = MLXSW_THERMAL_MAX_STATE;
599 return 0;
600 }
601
mlxsw_thermal_get_cur_state(struct thermal_cooling_device * cdev,unsigned long * p_state)602 static int mlxsw_thermal_get_cur_state(struct thermal_cooling_device *cdev,
603 unsigned long *p_state)
604
605 {
606 struct mlxsw_thermal *thermal = cdev->devdata;
607 struct device *dev = thermal->bus_info->dev;
608 char mfsc_pl[MLXSW_REG_MFSC_LEN];
609 int err, idx;
610 u8 duty;
611
612 idx = mlxsw_get_cooling_device_idx(thermal, cdev);
613 if (idx < 0)
614 return idx;
615
616 mlxsw_reg_mfsc_pack(mfsc_pl, idx, 0);
617 err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfsc), mfsc_pl);
618 if (err) {
619 dev_err(dev, "Failed to query PWM duty\n");
620 return err;
621 }
622
623 duty = mlxsw_reg_mfsc_pwm_duty_cycle_get(mfsc_pl);
624 *p_state = mlxsw_duty_to_state(duty);
625 return 0;
626 }
627
mlxsw_thermal_set_cur_state(struct thermal_cooling_device * cdev,unsigned long state)628 static int mlxsw_thermal_set_cur_state(struct thermal_cooling_device *cdev,
629 unsigned long state)
630
631 {
632 struct mlxsw_thermal *thermal = cdev->devdata;
633 struct device *dev = thermal->bus_info->dev;
634 char mfsc_pl[MLXSW_REG_MFSC_LEN];
635 unsigned long cur_state, i;
636 int idx;
637 u8 duty;
638 int err;
639
640 idx = mlxsw_get_cooling_device_idx(thermal, cdev);
641 if (idx < 0)
642 return idx;
643
644 /* Verify if this request is for changing allowed fan dynamical
645 * minimum. If it is - update cooling levels accordingly and update
646 * state, if current state is below the newly requested minimum state.
647 * For example, if current state is 5, and minimal state is to be
648 * changed from 4 to 6, thermal->cooling_levels[0 to 5] will be changed
649 * all from 4 to 6. And state 5 (thermal->cooling_levels[4]) should be
650 * overwritten.
651 */
652 if (state >= MLXSW_THERMAL_SPEED_MIN &&
653 state <= MLXSW_THERMAL_SPEED_MAX) {
654 state -= MLXSW_THERMAL_MAX_STATE;
655 for (i = 0; i <= MLXSW_THERMAL_MAX_STATE; i++)
656 thermal->cooling_levels[i] = max(state, i);
657
658 mlxsw_reg_mfsc_pack(mfsc_pl, idx, 0);
659 err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfsc), mfsc_pl);
660 if (err)
661 return err;
662
663 duty = mlxsw_reg_mfsc_pwm_duty_cycle_get(mfsc_pl);
664 cur_state = mlxsw_duty_to_state(duty);
665
666 /* If current fan state is lower than requested dynamical
667 * minimum, increase fan speed up to dynamical minimum.
668 */
669 if (state < cur_state)
670 return 0;
671
672 state = cur_state;
673 }
674
675 if (state > MLXSW_THERMAL_MAX_STATE)
676 return -EINVAL;
677
678 /* Normalize the state to the valid speed range. */
679 state = thermal->cooling_levels[state];
680 mlxsw_reg_mfsc_pack(mfsc_pl, idx, mlxsw_state_to_duty(state));
681 err = mlxsw_reg_write(thermal->core, MLXSW_REG(mfsc), mfsc_pl);
682 if (err) {
683 dev_err(dev, "Failed to write PWM duty\n");
684 return err;
685 }
686 return 0;
687 }
688
689 static const struct thermal_cooling_device_ops mlxsw_cooling_ops = {
690 .get_max_state = mlxsw_thermal_get_max_state,
691 .get_cur_state = mlxsw_thermal_get_cur_state,
692 .set_cur_state = mlxsw_thermal_set_cur_state,
693 };
694
695 static int
mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module * module_tz)696 mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz)
697 {
698 char tz_name[MLXSW_THERMAL_ZONE_MAX_NAME];
699 int err;
700
701 snprintf(tz_name, sizeof(tz_name), "mlxsw-module%d",
702 module_tz->module + 1);
703 module_tz->tzdev = thermal_zone_device_register(tz_name,
704 MLXSW_THERMAL_NUM_TRIPS,
705 MLXSW_THERMAL_TRIP_MASK,
706 module_tz,
707 &mlxsw_thermal_module_ops,
708 NULL, 0, 0);
709 if (IS_ERR(module_tz->tzdev)) {
710 err = PTR_ERR(module_tz->tzdev);
711 return err;
712 }
713
714 err = thermal_zone_device_enable(module_tz->tzdev);
715 if (err)
716 thermal_zone_device_unregister(module_tz->tzdev);
717
718 return err;
719 }
720
mlxsw_thermal_module_tz_fini(struct thermal_zone_device * tzdev)721 static void mlxsw_thermal_module_tz_fini(struct thermal_zone_device *tzdev)
722 {
723 thermal_zone_device_unregister(tzdev);
724 }
725
726 static int
mlxsw_thermal_module_init(struct device * dev,struct mlxsw_core * core,struct mlxsw_thermal * thermal,u8 module)727 mlxsw_thermal_module_init(struct device *dev, struct mlxsw_core *core,
728 struct mlxsw_thermal *thermal, u8 module)
729 {
730 struct mlxsw_thermal_module *module_tz;
731
732 module_tz = &thermal->tz_module_arr[module];
733 /* Skip if parent is already set (case of port split). */
734 if (module_tz->parent)
735 return 0;
736 module_tz->module = module;
737 module_tz->parent = thermal;
738 memcpy(module_tz->trips, default_thermal_trips,
739 sizeof(thermal->trips));
740 /* Initialize all trip point. */
741 mlxsw_thermal_module_trips_reset(module_tz);
742 /* Update trip point according to the module data. */
743 return mlxsw_thermal_module_trips_update(dev, core, module_tz);
744 }
745
mlxsw_thermal_module_fini(struct mlxsw_thermal_module * module_tz)746 static void mlxsw_thermal_module_fini(struct mlxsw_thermal_module *module_tz)
747 {
748 if (module_tz && module_tz->tzdev) {
749 mlxsw_thermal_module_tz_fini(module_tz->tzdev);
750 module_tz->tzdev = NULL;
751 module_tz->parent = NULL;
752 }
753 }
754
755 static int
mlxsw_thermal_modules_init(struct device * dev,struct mlxsw_core * core,struct mlxsw_thermal * thermal)756 mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core,
757 struct mlxsw_thermal *thermal)
758 {
759 struct mlxsw_thermal_module *module_tz;
760 char mgpir_pl[MLXSW_REG_MGPIR_LEN];
761 int i, err;
762
763 if (!mlxsw_core_res_query_enabled(core))
764 return 0;
765
766 mlxsw_reg_mgpir_pack(mgpir_pl);
767 err = mlxsw_reg_query(core, MLXSW_REG(mgpir), mgpir_pl);
768 if (err)
769 return err;
770
771 mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL,
772 &thermal->tz_module_num);
773
774 thermal->tz_module_arr = kcalloc(thermal->tz_module_num,
775 sizeof(*thermal->tz_module_arr),
776 GFP_KERNEL);
777 if (!thermal->tz_module_arr)
778 return -ENOMEM;
779
780 for (i = 0; i < thermal->tz_module_num; i++) {
781 err = mlxsw_thermal_module_init(dev, core, thermal, i);
782 if (err)
783 goto err_unreg_tz_module_arr;
784 }
785
786 for (i = 0; i < thermal->tz_module_num; i++) {
787 module_tz = &thermal->tz_module_arr[i];
788 if (!module_tz->parent)
789 continue;
790 err = mlxsw_thermal_module_tz_init(module_tz);
791 if (err)
792 goto err_unreg_tz_module_arr;
793 }
794
795 return 0;
796
797 err_unreg_tz_module_arr:
798 for (i = thermal->tz_module_num - 1; i >= 0; i--)
799 mlxsw_thermal_module_fini(&thermal->tz_module_arr[i]);
800 kfree(thermal->tz_module_arr);
801 return err;
802 }
803
804 static void
mlxsw_thermal_modules_fini(struct mlxsw_thermal * thermal)805 mlxsw_thermal_modules_fini(struct mlxsw_thermal *thermal)
806 {
807 int i;
808
809 if (!mlxsw_core_res_query_enabled(thermal->core))
810 return;
811
812 for (i = thermal->tz_module_num - 1; i >= 0; i--)
813 mlxsw_thermal_module_fini(&thermal->tz_module_arr[i]);
814 kfree(thermal->tz_module_arr);
815 }
816
817 static int
mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module * gearbox_tz)818 mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz)
819 {
820 char tz_name[MLXSW_THERMAL_ZONE_MAX_NAME];
821 int ret;
822
823 snprintf(tz_name, sizeof(tz_name), "mlxsw-gearbox%d",
824 gearbox_tz->module + 1);
825 gearbox_tz->tzdev = thermal_zone_device_register(tz_name,
826 MLXSW_THERMAL_NUM_TRIPS,
827 MLXSW_THERMAL_TRIP_MASK,
828 gearbox_tz,
829 &mlxsw_thermal_gearbox_ops,
830 NULL, 0, 0);
831 if (IS_ERR(gearbox_tz->tzdev))
832 return PTR_ERR(gearbox_tz->tzdev);
833
834 ret = thermal_zone_device_enable(gearbox_tz->tzdev);
835 if (ret)
836 thermal_zone_device_unregister(gearbox_tz->tzdev);
837
838 return ret;
839 }
840
841 static void
mlxsw_thermal_gearbox_tz_fini(struct mlxsw_thermal_module * gearbox_tz)842 mlxsw_thermal_gearbox_tz_fini(struct mlxsw_thermal_module *gearbox_tz)
843 {
844 thermal_zone_device_unregister(gearbox_tz->tzdev);
845 }
846
847 static int
mlxsw_thermal_gearboxes_init(struct device * dev,struct mlxsw_core * core,struct mlxsw_thermal * thermal)848 mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core,
849 struct mlxsw_thermal *thermal)
850 {
851 enum mlxsw_reg_mgpir_device_type device_type;
852 struct mlxsw_thermal_module *gearbox_tz;
853 char mgpir_pl[MLXSW_REG_MGPIR_LEN];
854 u8 gbox_num;
855 int i;
856 int err;
857
858 if (!mlxsw_core_res_query_enabled(core))
859 return 0;
860
861 mlxsw_reg_mgpir_pack(mgpir_pl);
862 err = mlxsw_reg_query(core, MLXSW_REG(mgpir), mgpir_pl);
863 if (err)
864 return err;
865
866 mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, &device_type, NULL,
867 NULL);
868 if (device_type != MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE ||
869 !gbox_num)
870 return 0;
871
872 thermal->tz_gearbox_num = gbox_num;
873 thermal->tz_gearbox_arr = kcalloc(thermal->tz_gearbox_num,
874 sizeof(*thermal->tz_gearbox_arr),
875 GFP_KERNEL);
876 if (!thermal->tz_gearbox_arr)
877 return -ENOMEM;
878
879 for (i = 0; i < thermal->tz_gearbox_num; i++) {
880 gearbox_tz = &thermal->tz_gearbox_arr[i];
881 memcpy(gearbox_tz->trips, default_thermal_trips,
882 sizeof(thermal->trips));
883 gearbox_tz->module = i;
884 gearbox_tz->parent = thermal;
885 err = mlxsw_thermal_gearbox_tz_init(gearbox_tz);
886 if (err)
887 goto err_unreg_tz_gearbox;
888 }
889
890 return 0;
891
892 err_unreg_tz_gearbox:
893 for (i--; i >= 0; i--)
894 mlxsw_thermal_gearbox_tz_fini(&thermal->tz_gearbox_arr[i]);
895 kfree(thermal->tz_gearbox_arr);
896 return err;
897 }
898
899 static void
mlxsw_thermal_gearboxes_fini(struct mlxsw_thermal * thermal)900 mlxsw_thermal_gearboxes_fini(struct mlxsw_thermal *thermal)
901 {
902 int i;
903
904 if (!mlxsw_core_res_query_enabled(thermal->core))
905 return;
906
907 for (i = thermal->tz_gearbox_num - 1; i >= 0; i--)
908 mlxsw_thermal_gearbox_tz_fini(&thermal->tz_gearbox_arr[i]);
909 kfree(thermal->tz_gearbox_arr);
910 }
911
mlxsw_thermal_init(struct mlxsw_core * core,const struct mlxsw_bus_info * bus_info,struct mlxsw_thermal ** p_thermal)912 int mlxsw_thermal_init(struct mlxsw_core *core,
913 const struct mlxsw_bus_info *bus_info,
914 struct mlxsw_thermal **p_thermal)
915 {
916 char mfcr_pl[MLXSW_REG_MFCR_LEN] = { 0 };
917 enum mlxsw_reg_mfcr_pwm_frequency freq;
918 struct device *dev = bus_info->dev;
919 struct mlxsw_thermal *thermal;
920 u16 tacho_active;
921 u8 pwm_active;
922 int err, i;
923
924 thermal = devm_kzalloc(dev, sizeof(*thermal),
925 GFP_KERNEL);
926 if (!thermal)
927 return -ENOMEM;
928
929 thermal->core = core;
930 thermal->bus_info = bus_info;
931 memcpy(thermal->trips, default_thermal_trips, sizeof(thermal->trips));
932
933 err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfcr), mfcr_pl);
934 if (err) {
935 dev_err(dev, "Failed to probe PWMs\n");
936 goto err_free_thermal;
937 }
938 mlxsw_reg_mfcr_unpack(mfcr_pl, &freq, &tacho_active, &pwm_active);
939
940 for (i = 0; i < MLXSW_MFCR_TACHOS_MAX; i++) {
941 if (tacho_active & BIT(i)) {
942 char mfsl_pl[MLXSW_REG_MFSL_LEN];
943
944 mlxsw_reg_mfsl_pack(mfsl_pl, i, 0, 0);
945
946 /* We need to query the register to preserve maximum */
947 err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfsl),
948 mfsl_pl);
949 if (err)
950 goto err_free_thermal;
951
952 /* set the minimal RPMs to 0 */
953 mlxsw_reg_mfsl_tach_min_set(mfsl_pl, 0);
954 err = mlxsw_reg_write(thermal->core, MLXSW_REG(mfsl),
955 mfsl_pl);
956 if (err)
957 goto err_free_thermal;
958 }
959 }
960 for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++) {
961 if (pwm_active & BIT(i)) {
962 struct thermal_cooling_device *cdev;
963
964 cdev = thermal_cooling_device_register("mlxsw_fan",
965 thermal,
966 &mlxsw_cooling_ops);
967 if (IS_ERR(cdev)) {
968 err = PTR_ERR(cdev);
969 dev_err(dev, "Failed to register cooling device\n");
970 goto err_unreg_cdevs;
971 }
972 thermal->cdevs[i] = cdev;
973 }
974 }
975
976 /* Initialize cooling levels per PWM state. */
977 for (i = 0; i < MLXSW_THERMAL_MAX_STATE; i++)
978 thermal->cooling_levels[i] = max(MLXSW_THERMAL_SPEED_MIN_LEVEL,
979 i);
980
981 thermal->polling_delay = bus_info->low_frequency ?
982 MLXSW_THERMAL_SLOW_POLL_INT :
983 MLXSW_THERMAL_POLL_INT;
984
985 thermal->tzdev = thermal_zone_device_register("mlxsw",
986 MLXSW_THERMAL_NUM_TRIPS,
987 MLXSW_THERMAL_TRIP_MASK,
988 thermal,
989 &mlxsw_thermal_ops,
990 NULL, 0,
991 thermal->polling_delay);
992 if (IS_ERR(thermal->tzdev)) {
993 err = PTR_ERR(thermal->tzdev);
994 dev_err(dev, "Failed to register thermal zone\n");
995 goto err_unreg_cdevs;
996 }
997
998 err = mlxsw_thermal_modules_init(dev, core, thermal);
999 if (err)
1000 goto err_unreg_tzdev;
1001
1002 err = mlxsw_thermal_gearboxes_init(dev, core, thermal);
1003 if (err)
1004 goto err_unreg_modules_tzdev;
1005
1006 err = thermal_zone_device_enable(thermal->tzdev);
1007 if (err)
1008 goto err_unreg_gearboxes;
1009
1010 *p_thermal = thermal;
1011 return 0;
1012
1013 err_unreg_gearboxes:
1014 mlxsw_thermal_gearboxes_fini(thermal);
1015 err_unreg_modules_tzdev:
1016 mlxsw_thermal_modules_fini(thermal);
1017 err_unreg_tzdev:
1018 if (thermal->tzdev) {
1019 thermal_zone_device_unregister(thermal->tzdev);
1020 thermal->tzdev = NULL;
1021 }
1022 err_unreg_cdevs:
1023 for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++)
1024 if (thermal->cdevs[i])
1025 thermal_cooling_device_unregister(thermal->cdevs[i]);
1026 err_free_thermal:
1027 devm_kfree(dev, thermal);
1028 return err;
1029 }
1030
mlxsw_thermal_fini(struct mlxsw_thermal * thermal)1031 void mlxsw_thermal_fini(struct mlxsw_thermal *thermal)
1032 {
1033 int i;
1034
1035 mlxsw_thermal_gearboxes_fini(thermal);
1036 mlxsw_thermal_modules_fini(thermal);
1037 if (thermal->tzdev) {
1038 thermal_zone_device_unregister(thermal->tzdev);
1039 thermal->tzdev = NULL;
1040 }
1041
1042 for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++) {
1043 if (thermal->cdevs[i]) {
1044 thermal_cooling_device_unregister(thermal->cdevs[i]);
1045 thermal->cdevs[i] = NULL;
1046 }
1047 }
1048
1049 devm_kfree(thermal->bus_info->dev, thermal);
1050 }
1051