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