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