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