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>
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>
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_ZONE_MAX_NAME 16
25 #define MLXSW_THERMAL_TEMP_SCORE_MAX GENMASK(31, 0)
26 #define MLXSW_THERMAL_MAX_STATE 10
27 #define MLXSW_THERMAL_MIN_STATE 2
28 #define MLXSW_THERMAL_MAX_DUTY 255
30 /* External cooling devices, allowed for binding to mlxsw thermal zones. */
31 static char * const mlxsw_thermal_external_allowed_cdev[] = {
35 enum mlxsw_thermal_trips {
36 MLXSW_THERMAL_TEMP_TRIP_NORM,
37 MLXSW_THERMAL_TEMP_TRIP_HIGH,
38 MLXSW_THERMAL_TEMP_TRIP_HOT,
41 struct mlxsw_thermal_trip {
49 static const struct mlxsw_thermal_trip default_thermal_trips[] = {
50 { /* In range - 0-40% PWM */
51 .type = THERMAL_TRIP_ACTIVE,
52 .temp = MLXSW_THERMAL_ASIC_TEMP_NORM,
53 .hyst = MLXSW_THERMAL_HYSTERESIS_TEMP,
55 .max_state = (4 * MLXSW_THERMAL_MAX_STATE) / 10,
58 /* In range - 40-100% PWM */
59 .type = THERMAL_TRIP_ACTIVE,
60 .temp = MLXSW_THERMAL_ASIC_TEMP_HIGH,
61 .hyst = MLXSW_THERMAL_HYSTERESIS_TEMP,
62 .min_state = (4 * MLXSW_THERMAL_MAX_STATE) / 10,
63 .max_state = MLXSW_THERMAL_MAX_STATE,
66 .type = THERMAL_TRIP_HOT,
67 .temp = MLXSW_THERMAL_ASIC_TEMP_HOT,
68 .min_state = MLXSW_THERMAL_MAX_STATE,
69 .max_state = MLXSW_THERMAL_MAX_STATE,
73 #define MLXSW_THERMAL_NUM_TRIPS ARRAY_SIZE(default_thermal_trips)
75 /* Make sure all trips are writable */
76 #define MLXSW_THERMAL_TRIP_MASK (BIT(MLXSW_THERMAL_NUM_TRIPS) - 1)
80 struct mlxsw_thermal_module {
81 struct mlxsw_thermal *parent;
82 struct thermal_zone_device *tzdev;
83 struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
84 int module; /* Module or gearbox number */
87 struct mlxsw_thermal {
88 struct mlxsw_core *core;
89 const struct mlxsw_bus_info *bus_info;
90 struct thermal_zone_device *tzdev;
92 struct thermal_cooling_device *cdevs[MLXSW_MFCR_PWMS_MAX];
93 u8 cooling_levels[MLXSW_THERMAL_MAX_STATE + 1];
94 struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
95 struct mlxsw_thermal_module *tz_module_arr;
97 struct mlxsw_thermal_module *tz_gearbox_arr;
99 unsigned int tz_highest_score;
100 struct thermal_zone_device *tz_highest_dev;
103 static inline u8 mlxsw_state_to_duty(int state)
105 return DIV_ROUND_CLOSEST(state * MLXSW_THERMAL_MAX_DUTY,
106 MLXSW_THERMAL_MAX_STATE);
109 static inline int mlxsw_duty_to_state(u8 duty)
111 return DIV_ROUND_CLOSEST(duty * MLXSW_THERMAL_MAX_STATE,
112 MLXSW_THERMAL_MAX_DUTY);
115 static int mlxsw_get_cooling_device_idx(struct mlxsw_thermal *thermal,
116 struct thermal_cooling_device *cdev)
120 for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++)
121 if (thermal->cdevs[i] == cdev)
124 /* Allow mlxsw thermal zone binding to an external cooling device */
125 for (i = 0; i < ARRAY_SIZE(mlxsw_thermal_external_allowed_cdev); i++) {
126 if (strnstr(cdev->type, mlxsw_thermal_external_allowed_cdev[i],
135 mlxsw_thermal_module_trips_reset(struct mlxsw_thermal_module *tz)
137 tz->trips[MLXSW_THERMAL_TEMP_TRIP_NORM].temp = 0;
138 tz->trips[MLXSW_THERMAL_TEMP_TRIP_HIGH].temp = 0;
139 tz->trips[MLXSW_THERMAL_TEMP_TRIP_HOT].temp = 0;
143 mlxsw_thermal_module_trips_update(struct device *dev, struct mlxsw_core *core,
144 struct mlxsw_thermal_module *tz,
145 int crit_temp, int emerg_temp)
149 /* Do not try to query temperature thresholds directly from the module's
150 * EEPROM if we got valid thresholds from MTMP.
152 if (!emerg_temp || !crit_temp) {
153 err = mlxsw_env_module_temp_thresholds_get(core, tz->module,
159 err = mlxsw_env_module_temp_thresholds_get(core, tz->module,
166 if (crit_temp > emerg_temp) {
167 dev_warn(dev, "%s : Critical threshold %d is above emergency threshold %d\n",
168 tz->tzdev->type, crit_temp, emerg_temp);
172 /* According to the system thermal requirements, the thermal zones are
173 * defined with three trip points. The critical and emergency
174 * temperature thresholds, provided by QSFP module are set as "active"
175 * and "hot" trip points, "normal" trip point is derived from "active"
176 * by subtracting double hysteresis value.
178 if (crit_temp >= MLXSW_THERMAL_MODULE_TEMP_SHIFT)
179 tz->trips[MLXSW_THERMAL_TEMP_TRIP_NORM].temp = crit_temp -
180 MLXSW_THERMAL_MODULE_TEMP_SHIFT;
182 tz->trips[MLXSW_THERMAL_TEMP_TRIP_NORM].temp = crit_temp;
183 tz->trips[MLXSW_THERMAL_TEMP_TRIP_HIGH].temp = crit_temp;
184 tz->trips[MLXSW_THERMAL_TEMP_TRIP_HOT].temp = emerg_temp;
189 static void mlxsw_thermal_tz_score_update(struct mlxsw_thermal *thermal,
190 struct thermal_zone_device *tzdev,
191 struct mlxsw_thermal_trip *trips,
194 struct mlxsw_thermal_trip *trip = trips;
195 unsigned int score, delta, i, shift = 1;
197 /* Calculate thermal zone score, if temperature is above the hot
198 * threshold score is set to MLXSW_THERMAL_TEMP_SCORE_MAX.
200 score = MLXSW_THERMAL_TEMP_SCORE_MAX;
201 for (i = MLXSW_THERMAL_TEMP_TRIP_NORM; i < MLXSW_THERMAL_NUM_TRIPS;
203 if (temp < trip->temp) {
204 delta = DIV_ROUND_CLOSEST(temp, trip->temp - temp);
205 score = delta * shift;
211 if (score > thermal->tz_highest_score) {
212 thermal->tz_highest_score = score;
213 thermal->tz_highest_dev = tzdev;
217 static int mlxsw_thermal_bind(struct thermal_zone_device *tzdev,
218 struct thermal_cooling_device *cdev)
220 struct mlxsw_thermal *thermal = tzdev->devdata;
221 struct device *dev = thermal->bus_info->dev;
224 /* If the cooling device is one of ours bind it */
225 if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0)
228 for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) {
229 const struct mlxsw_thermal_trip *trip = &thermal->trips[i];
231 err = thermal_zone_bind_cooling_device(tzdev, i, cdev,
234 THERMAL_WEIGHT_DEFAULT);
236 dev_err(dev, "Failed to bind cooling device to trip %d\n", i);
243 static int mlxsw_thermal_unbind(struct thermal_zone_device *tzdev,
244 struct thermal_cooling_device *cdev)
246 struct mlxsw_thermal *thermal = tzdev->devdata;
247 struct device *dev = thermal->bus_info->dev;
251 /* If the cooling device is our one unbind it */
252 if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0)
255 for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) {
256 err = thermal_zone_unbind_cooling_device(tzdev, i, cdev);
258 dev_err(dev, "Failed to unbind cooling device\n");
265 static int mlxsw_thermal_get_temp(struct thermal_zone_device *tzdev,
268 struct mlxsw_thermal *thermal = tzdev->devdata;
269 struct device *dev = thermal->bus_info->dev;
270 char mtmp_pl[MLXSW_REG_MTMP_LEN];
274 mlxsw_reg_mtmp_pack(mtmp_pl, 0, false, false);
276 err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl);
278 dev_err(dev, "Failed to query temp sensor\n");
281 mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL, NULL, NULL);
283 mlxsw_thermal_tz_score_update(thermal, tzdev, thermal->trips,
290 static int mlxsw_thermal_get_trip_type(struct thermal_zone_device *tzdev,
292 enum thermal_trip_type *p_type)
294 struct mlxsw_thermal *thermal = tzdev->devdata;
296 if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
299 *p_type = thermal->trips[trip].type;
303 static int mlxsw_thermal_get_trip_temp(struct thermal_zone_device *tzdev,
304 int trip, int *p_temp)
306 struct mlxsw_thermal *thermal = tzdev->devdata;
308 if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
311 *p_temp = thermal->trips[trip].temp;
315 static int mlxsw_thermal_set_trip_temp(struct thermal_zone_device *tzdev,
318 struct mlxsw_thermal *thermal = tzdev->devdata;
320 if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
323 thermal->trips[trip].temp = temp;
327 static int mlxsw_thermal_get_trip_hyst(struct thermal_zone_device *tzdev,
328 int trip, int *p_hyst)
330 struct mlxsw_thermal *thermal = tzdev->devdata;
332 *p_hyst = thermal->trips[trip].hyst;
336 static int mlxsw_thermal_set_trip_hyst(struct thermal_zone_device *tzdev,
339 struct mlxsw_thermal *thermal = tzdev->devdata;
341 thermal->trips[trip].hyst = hyst;
345 static int mlxsw_thermal_trend_get(struct thermal_zone_device *tzdev,
346 int trip, enum thermal_trend *trend)
348 struct mlxsw_thermal *thermal = tzdev->devdata;
350 if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
353 if (tzdev == thermal->tz_highest_dev)
356 *trend = THERMAL_TREND_STABLE;
360 static struct thermal_zone_device_ops mlxsw_thermal_ops = {
361 .bind = mlxsw_thermal_bind,
362 .unbind = mlxsw_thermal_unbind,
363 .get_temp = mlxsw_thermal_get_temp,
364 .get_trip_type = mlxsw_thermal_get_trip_type,
365 .get_trip_temp = mlxsw_thermal_get_trip_temp,
366 .set_trip_temp = mlxsw_thermal_set_trip_temp,
367 .get_trip_hyst = mlxsw_thermal_get_trip_hyst,
368 .set_trip_hyst = mlxsw_thermal_set_trip_hyst,
369 .get_trend = mlxsw_thermal_trend_get,
372 static int mlxsw_thermal_module_bind(struct thermal_zone_device *tzdev,
373 struct thermal_cooling_device *cdev)
375 struct mlxsw_thermal_module *tz = tzdev->devdata;
376 struct mlxsw_thermal *thermal = tz->parent;
379 /* If the cooling device is one of ours bind it */
380 if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0)
383 for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) {
384 const struct mlxsw_thermal_trip *trip = &tz->trips[i];
386 err = thermal_zone_bind_cooling_device(tzdev, i, cdev,
389 THERMAL_WEIGHT_DEFAULT);
391 goto err_bind_cooling_device;
395 err_bind_cooling_device:
396 for (j = i - 1; j >= 0; j--)
397 thermal_zone_unbind_cooling_device(tzdev, j, cdev);
401 static int mlxsw_thermal_module_unbind(struct thermal_zone_device *tzdev,
402 struct thermal_cooling_device *cdev)
404 struct mlxsw_thermal_module *tz = tzdev->devdata;
405 struct mlxsw_thermal *thermal = tz->parent;
409 /* If the cooling device is one of ours unbind it */
410 if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0)
413 for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) {
414 err = thermal_zone_unbind_cooling_device(tzdev, i, cdev);
421 mlxsw_thermal_module_temp_and_thresholds_get(struct mlxsw_core *core,
422 u16 sensor_index, int *p_temp,
426 char mtmp_pl[MLXSW_REG_MTMP_LEN];
429 /* Read module temperature and thresholds. */
430 mlxsw_reg_mtmp_pack(mtmp_pl, sensor_index, false, false);
431 err = mlxsw_reg_query(core, MLXSW_REG(mtmp), mtmp_pl);
433 /* Set temperature and thresholds to zero to avoid passing
434 * uninitialized data back to the caller.
442 mlxsw_reg_mtmp_unpack(mtmp_pl, p_temp, NULL, p_crit_temp, p_emerg_temp,
446 static int mlxsw_thermal_module_temp_get(struct thermal_zone_device *tzdev,
449 struct mlxsw_thermal_module *tz = tzdev->devdata;
450 struct mlxsw_thermal *thermal = tz->parent;
451 int temp, crit_temp, emerg_temp;
456 dev = thermal->bus_info->dev;
457 sensor_index = MLXSW_REG_MTMP_MODULE_INDEX_MIN + tz->module;
459 /* Read module temperature and thresholds. */
460 mlxsw_thermal_module_temp_and_thresholds_get(thermal->core,
462 &crit_temp, &emerg_temp);
468 /* Update trip points. */
469 err = mlxsw_thermal_module_trips_update(dev, thermal->core, tz,
470 crit_temp, emerg_temp);
471 if (!err && temp > 0)
472 mlxsw_thermal_tz_score_update(thermal, tzdev, tz->trips, temp);
478 mlxsw_thermal_module_trip_type_get(struct thermal_zone_device *tzdev, int trip,
479 enum thermal_trip_type *p_type)
481 struct mlxsw_thermal_module *tz = tzdev->devdata;
483 if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
486 *p_type = tz->trips[trip].type;
491 mlxsw_thermal_module_trip_temp_get(struct thermal_zone_device *tzdev,
492 int trip, int *p_temp)
494 struct mlxsw_thermal_module *tz = tzdev->devdata;
496 if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
499 *p_temp = tz->trips[trip].temp;
504 mlxsw_thermal_module_trip_temp_set(struct thermal_zone_device *tzdev,
507 struct mlxsw_thermal_module *tz = tzdev->devdata;
509 if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
512 tz->trips[trip].temp = temp;
517 mlxsw_thermal_module_trip_hyst_get(struct thermal_zone_device *tzdev, int trip,
520 struct mlxsw_thermal_module *tz = tzdev->devdata;
522 *p_hyst = tz->trips[trip].hyst;
527 mlxsw_thermal_module_trip_hyst_set(struct thermal_zone_device *tzdev, int trip,
530 struct mlxsw_thermal_module *tz = tzdev->devdata;
532 tz->trips[trip].hyst = hyst;
536 static int mlxsw_thermal_module_trend_get(struct thermal_zone_device *tzdev,
537 int trip, enum thermal_trend *trend)
539 struct mlxsw_thermal_module *tz = tzdev->devdata;
540 struct mlxsw_thermal *thermal = tz->parent;
542 if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
545 if (tzdev == thermal->tz_highest_dev)
548 *trend = THERMAL_TREND_STABLE;
552 static struct thermal_zone_device_ops mlxsw_thermal_module_ops = {
553 .bind = mlxsw_thermal_module_bind,
554 .unbind = mlxsw_thermal_module_unbind,
555 .get_temp = mlxsw_thermal_module_temp_get,
556 .get_trip_type = mlxsw_thermal_module_trip_type_get,
557 .get_trip_temp = mlxsw_thermal_module_trip_temp_get,
558 .set_trip_temp = mlxsw_thermal_module_trip_temp_set,
559 .get_trip_hyst = mlxsw_thermal_module_trip_hyst_get,
560 .set_trip_hyst = mlxsw_thermal_module_trip_hyst_set,
561 .get_trend = mlxsw_thermal_module_trend_get,
564 static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev,
567 struct mlxsw_thermal_module *tz = tzdev->devdata;
568 struct mlxsw_thermal *thermal = tz->parent;
569 char mtmp_pl[MLXSW_REG_MTMP_LEN];
574 index = MLXSW_REG_MTMP_GBOX_INDEX_MIN + tz->module;
575 mlxsw_reg_mtmp_pack(mtmp_pl, index, false, false);
577 err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl);
581 mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL, NULL, NULL);
583 mlxsw_thermal_tz_score_update(thermal, tzdev, tz->trips, temp);
589 static struct thermal_zone_device_ops mlxsw_thermal_gearbox_ops = {
590 .bind = mlxsw_thermal_module_bind,
591 .unbind = mlxsw_thermal_module_unbind,
592 .get_temp = mlxsw_thermal_gearbox_temp_get,
593 .get_trip_type = mlxsw_thermal_module_trip_type_get,
594 .get_trip_temp = mlxsw_thermal_module_trip_temp_get,
595 .set_trip_temp = mlxsw_thermal_module_trip_temp_set,
596 .get_trip_hyst = mlxsw_thermal_module_trip_hyst_get,
597 .set_trip_hyst = mlxsw_thermal_module_trip_hyst_set,
598 .get_trend = mlxsw_thermal_module_trend_get,
601 static int mlxsw_thermal_get_max_state(struct thermal_cooling_device *cdev,
602 unsigned long *p_state)
604 *p_state = MLXSW_THERMAL_MAX_STATE;
608 static int mlxsw_thermal_get_cur_state(struct thermal_cooling_device *cdev,
609 unsigned long *p_state)
612 struct mlxsw_thermal *thermal = cdev->devdata;
613 struct device *dev = thermal->bus_info->dev;
614 char mfsc_pl[MLXSW_REG_MFSC_LEN];
618 idx = mlxsw_get_cooling_device_idx(thermal, cdev);
622 mlxsw_reg_mfsc_pack(mfsc_pl, idx, 0);
623 err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfsc), mfsc_pl);
625 dev_err(dev, "Failed to query PWM duty\n");
629 duty = mlxsw_reg_mfsc_pwm_duty_cycle_get(mfsc_pl);
630 *p_state = mlxsw_duty_to_state(duty);
634 static int mlxsw_thermal_set_cur_state(struct thermal_cooling_device *cdev,
638 struct mlxsw_thermal *thermal = cdev->devdata;
639 struct device *dev = thermal->bus_info->dev;
640 char mfsc_pl[MLXSW_REG_MFSC_LEN];
644 if (state > MLXSW_THERMAL_MAX_STATE)
647 idx = mlxsw_get_cooling_device_idx(thermal, cdev);
651 /* Normalize the state to the valid speed range. */
652 state = thermal->cooling_levels[state];
653 mlxsw_reg_mfsc_pack(mfsc_pl, idx, mlxsw_state_to_duty(state));
654 err = mlxsw_reg_write(thermal->core, MLXSW_REG(mfsc), mfsc_pl);
656 dev_err(dev, "Failed to write PWM duty\n");
662 static const struct thermal_cooling_device_ops mlxsw_cooling_ops = {
663 .get_max_state = mlxsw_thermal_get_max_state,
664 .get_cur_state = mlxsw_thermal_get_cur_state,
665 .set_cur_state = mlxsw_thermal_set_cur_state,
669 mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz)
671 char tz_name[MLXSW_THERMAL_ZONE_MAX_NAME];
674 snprintf(tz_name, sizeof(tz_name), "mlxsw-module%d",
675 module_tz->module + 1);
676 module_tz->tzdev = thermal_zone_device_register(tz_name,
677 MLXSW_THERMAL_NUM_TRIPS,
678 MLXSW_THERMAL_TRIP_MASK,
680 &mlxsw_thermal_module_ops,
682 module_tz->parent->polling_delay);
683 if (IS_ERR(module_tz->tzdev)) {
684 err = PTR_ERR(module_tz->tzdev);
688 err = thermal_zone_device_enable(module_tz->tzdev);
690 thermal_zone_device_unregister(module_tz->tzdev);
695 static void mlxsw_thermal_module_tz_fini(struct thermal_zone_device *tzdev)
697 thermal_zone_device_unregister(tzdev);
701 mlxsw_thermal_module_init(struct device *dev, struct mlxsw_core *core,
702 struct mlxsw_thermal *thermal, u8 module)
704 struct mlxsw_thermal_module *module_tz;
705 int dummy_temp, crit_temp, emerg_temp;
708 sensor_index = MLXSW_REG_MTMP_MODULE_INDEX_MIN + module;
709 module_tz = &thermal->tz_module_arr[module];
710 /* Skip if parent is already set (case of port split). */
711 if (module_tz->parent)
713 module_tz->module = module;
714 module_tz->parent = thermal;
715 memcpy(module_tz->trips, default_thermal_trips,
716 sizeof(thermal->trips));
717 /* Initialize all trip point. */
718 mlxsw_thermal_module_trips_reset(module_tz);
719 /* Read module temperature and thresholds. */
720 mlxsw_thermal_module_temp_and_thresholds_get(core, sensor_index, &dummy_temp,
721 &crit_temp, &emerg_temp);
722 /* Update trip point according to the module data. */
723 return mlxsw_thermal_module_trips_update(dev, core, module_tz,
724 crit_temp, emerg_temp);
727 static void mlxsw_thermal_module_fini(struct mlxsw_thermal_module *module_tz)
729 if (module_tz && module_tz->tzdev) {
730 mlxsw_thermal_module_tz_fini(module_tz->tzdev);
731 module_tz->tzdev = NULL;
732 module_tz->parent = NULL;
737 mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core,
738 struct mlxsw_thermal *thermal)
740 struct mlxsw_thermal_module *module_tz;
741 char mgpir_pl[MLXSW_REG_MGPIR_LEN];
744 if (!mlxsw_core_res_query_enabled(core))
747 mlxsw_reg_mgpir_pack(mgpir_pl);
748 err = mlxsw_reg_query(core, MLXSW_REG(mgpir), mgpir_pl);
752 mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL,
753 &thermal->tz_module_num);
755 thermal->tz_module_arr = kcalloc(thermal->tz_module_num,
756 sizeof(*thermal->tz_module_arr),
758 if (!thermal->tz_module_arr)
761 for (i = 0; i < thermal->tz_module_num; i++) {
762 err = mlxsw_thermal_module_init(dev, core, thermal, i);
764 goto err_unreg_tz_module_arr;
767 for (i = 0; i < thermal->tz_module_num; i++) {
768 module_tz = &thermal->tz_module_arr[i];
769 if (!module_tz->parent)
771 err = mlxsw_thermal_module_tz_init(module_tz);
773 goto err_unreg_tz_module_arr;
778 err_unreg_tz_module_arr:
779 for (i = thermal->tz_module_num - 1; i >= 0; i--)
780 mlxsw_thermal_module_fini(&thermal->tz_module_arr[i]);
781 kfree(thermal->tz_module_arr);
786 mlxsw_thermal_modules_fini(struct mlxsw_thermal *thermal)
790 if (!mlxsw_core_res_query_enabled(thermal->core))
793 for (i = thermal->tz_module_num - 1; i >= 0; i--)
794 mlxsw_thermal_module_fini(&thermal->tz_module_arr[i]);
795 kfree(thermal->tz_module_arr);
799 mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz)
801 char tz_name[MLXSW_THERMAL_ZONE_MAX_NAME];
804 snprintf(tz_name, sizeof(tz_name), "mlxsw-gearbox%d",
805 gearbox_tz->module + 1);
806 gearbox_tz->tzdev = thermal_zone_device_register(tz_name,
807 MLXSW_THERMAL_NUM_TRIPS,
808 MLXSW_THERMAL_TRIP_MASK,
810 &mlxsw_thermal_gearbox_ops,
812 gearbox_tz->parent->polling_delay);
813 if (IS_ERR(gearbox_tz->tzdev))
814 return PTR_ERR(gearbox_tz->tzdev);
816 ret = thermal_zone_device_enable(gearbox_tz->tzdev);
818 thermal_zone_device_unregister(gearbox_tz->tzdev);
824 mlxsw_thermal_gearbox_tz_fini(struct mlxsw_thermal_module *gearbox_tz)
826 thermal_zone_device_unregister(gearbox_tz->tzdev);
830 mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core,
831 struct mlxsw_thermal *thermal)
833 enum mlxsw_reg_mgpir_device_type device_type;
834 struct mlxsw_thermal_module *gearbox_tz;
835 char mgpir_pl[MLXSW_REG_MGPIR_LEN];
840 if (!mlxsw_core_res_query_enabled(core))
843 mlxsw_reg_mgpir_pack(mgpir_pl);
844 err = mlxsw_reg_query(core, MLXSW_REG(mgpir), mgpir_pl);
848 mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, &device_type, NULL,
850 if (device_type != MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE ||
854 thermal->tz_gearbox_num = gbox_num;
855 thermal->tz_gearbox_arr = kcalloc(thermal->tz_gearbox_num,
856 sizeof(*thermal->tz_gearbox_arr),
858 if (!thermal->tz_gearbox_arr)
861 for (i = 0; i < thermal->tz_gearbox_num; i++) {
862 gearbox_tz = &thermal->tz_gearbox_arr[i];
863 memcpy(gearbox_tz->trips, default_thermal_trips,
864 sizeof(thermal->trips));
865 gearbox_tz->module = i;
866 gearbox_tz->parent = thermal;
867 err = mlxsw_thermal_gearbox_tz_init(gearbox_tz);
869 goto err_unreg_tz_gearbox;
874 err_unreg_tz_gearbox:
875 for (i--; i >= 0; i--)
876 mlxsw_thermal_gearbox_tz_fini(&thermal->tz_gearbox_arr[i]);
877 kfree(thermal->tz_gearbox_arr);
882 mlxsw_thermal_gearboxes_fini(struct mlxsw_thermal *thermal)
886 if (!mlxsw_core_res_query_enabled(thermal->core))
889 for (i = thermal->tz_gearbox_num - 1; i >= 0; i--)
890 mlxsw_thermal_gearbox_tz_fini(&thermal->tz_gearbox_arr[i]);
891 kfree(thermal->tz_gearbox_arr);
894 int mlxsw_thermal_init(struct mlxsw_core *core,
895 const struct mlxsw_bus_info *bus_info,
896 struct mlxsw_thermal **p_thermal)
898 char mfcr_pl[MLXSW_REG_MFCR_LEN] = { 0 };
899 enum mlxsw_reg_mfcr_pwm_frequency freq;
900 struct device *dev = bus_info->dev;
901 struct mlxsw_thermal *thermal;
906 thermal = devm_kzalloc(dev, sizeof(*thermal),
911 thermal->core = core;
912 thermal->bus_info = bus_info;
913 memcpy(thermal->trips, default_thermal_trips, sizeof(thermal->trips));
915 err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfcr), mfcr_pl);
917 dev_err(dev, "Failed to probe PWMs\n");
918 goto err_free_thermal;
920 mlxsw_reg_mfcr_unpack(mfcr_pl, &freq, &tacho_active, &pwm_active);
922 for (i = 0; i < MLXSW_MFCR_TACHOS_MAX; i++) {
923 if (tacho_active & BIT(i)) {
924 char mfsl_pl[MLXSW_REG_MFSL_LEN];
926 mlxsw_reg_mfsl_pack(mfsl_pl, i, 0, 0);
928 /* We need to query the register to preserve maximum */
929 err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfsl),
932 goto err_free_thermal;
934 /* set the minimal RPMs to 0 */
935 mlxsw_reg_mfsl_tach_min_set(mfsl_pl, 0);
936 err = mlxsw_reg_write(thermal->core, MLXSW_REG(mfsl),
939 goto err_free_thermal;
942 for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++) {
943 if (pwm_active & BIT(i)) {
944 struct thermal_cooling_device *cdev;
946 cdev = thermal_cooling_device_register("mlxsw_fan",
951 dev_err(dev, "Failed to register cooling device\n");
952 goto err_unreg_cdevs;
954 thermal->cdevs[i] = cdev;
958 /* Initialize cooling levels per PWM state. */
959 for (i = 0; i < MLXSW_THERMAL_MAX_STATE; i++)
960 thermal->cooling_levels[i] = max(MLXSW_THERMAL_MIN_STATE, i);
962 thermal->polling_delay = bus_info->low_frequency ?
963 MLXSW_THERMAL_SLOW_POLL_INT :
964 MLXSW_THERMAL_POLL_INT;
966 thermal->tzdev = thermal_zone_device_register("mlxsw",
967 MLXSW_THERMAL_NUM_TRIPS,
968 MLXSW_THERMAL_TRIP_MASK,
972 thermal->polling_delay);
973 if (IS_ERR(thermal->tzdev)) {
974 err = PTR_ERR(thermal->tzdev);
975 dev_err(dev, "Failed to register thermal zone\n");
976 goto err_unreg_cdevs;
979 err = mlxsw_thermal_modules_init(dev, core, thermal);
981 goto err_unreg_tzdev;
983 err = mlxsw_thermal_gearboxes_init(dev, core, thermal);
985 goto err_unreg_modules_tzdev;
987 err = thermal_zone_device_enable(thermal->tzdev);
989 goto err_unreg_gearboxes;
991 *p_thermal = thermal;
995 mlxsw_thermal_gearboxes_fini(thermal);
996 err_unreg_modules_tzdev:
997 mlxsw_thermal_modules_fini(thermal);
999 if (thermal->tzdev) {
1000 thermal_zone_device_unregister(thermal->tzdev);
1001 thermal->tzdev = NULL;
1004 for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++)
1005 if (thermal->cdevs[i])
1006 thermal_cooling_device_unregister(thermal->cdevs[i]);
1008 devm_kfree(dev, thermal);
1012 void mlxsw_thermal_fini(struct mlxsw_thermal *thermal)
1016 mlxsw_thermal_gearboxes_fini(thermal);
1017 mlxsw_thermal_modules_fini(thermal);
1018 if (thermal->tzdev) {
1019 thermal_zone_device_unregister(thermal->tzdev);
1020 thermal->tzdev = NULL;
1023 for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++) {
1024 if (thermal->cdevs[i]) {
1025 thermal_cooling_device_unregister(thermal->cdevs[i]);
1026 thermal->cdevs[i] = NULL;
1030 devm_kfree(thermal->bus_info->dev, thermal);