root/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mlxsw_state_to_duty
  2. mlxsw_duty_to_state
  3. mlxsw_get_cooling_device_idx
  4. mlxsw_thermal_module_trips_reset
  5. mlxsw_thermal_module_trips_update
  6. mlxsw_thermal_tz_score_update
  7. mlxsw_thermal_bind
  8. mlxsw_thermal_unbind
  9. mlxsw_thermal_get_mode
  10. mlxsw_thermal_set_mode
  11. mlxsw_thermal_get_temp
  12. mlxsw_thermal_get_trip_type
  13. mlxsw_thermal_get_trip_temp
  14. mlxsw_thermal_set_trip_temp
  15. mlxsw_thermal_get_trip_hyst
  16. mlxsw_thermal_set_trip_hyst
  17. mlxsw_thermal_trend_get
  18. mlxsw_thermal_module_bind
  19. mlxsw_thermal_module_unbind
  20. mlxsw_thermal_module_mode_get
  21. mlxsw_thermal_module_mode_set
  22. mlxsw_thermal_module_temp_get
  23. mlxsw_thermal_module_trip_type_get
  24. mlxsw_thermal_module_trip_temp_get
  25. mlxsw_thermal_module_trip_temp_set
  26. mlxsw_thermal_module_trip_hyst_get
  27. mlxsw_thermal_module_trip_hyst_set
  28. mlxsw_thermal_module_trend_get
  29. mlxsw_thermal_gearbox_temp_get
  30. mlxsw_thermal_get_max_state
  31. mlxsw_thermal_get_cur_state
  32. mlxsw_thermal_set_cur_state
  33. mlxsw_thermal_module_tz_init
  34. mlxsw_thermal_module_tz_fini
  35. mlxsw_thermal_module_init
  36. mlxsw_thermal_module_fini
  37. mlxsw_thermal_modules_init
  38. mlxsw_thermal_modules_fini
  39. mlxsw_thermal_gearbox_tz_init
  40. mlxsw_thermal_gearbox_tz_fini
  41. mlxsw_thermal_gearboxes_init
  42. mlxsw_thermal_gearboxes_fini
  43. mlxsw_thermal_init
  44. mlxsw_thermal_fini

   1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2 /* Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved
   3  * Copyright (c) 2016 Ivan Vecera <cera@cera.cz>
   4  */
   5 
   6 #include <linux/kernel.h>
   7 #include <linux/types.h>
   8 #include <linux/device.h>
   9 #include <linux/sysfs.h>
  10 #include <linux/thermal.h>
  11 #include <linux/err.h>
  12 #include <linux/sfp.h>
  13 
  14 #include "core.h"
  15 #include "core_env.h"
  16 
  17 #define MLXSW_THERMAL_POLL_INT  1000    /* ms */
  18 #define MLXSW_THERMAL_SLOW_POLL_INT     20000   /* ms */
  19 #define MLXSW_THERMAL_ASIC_TEMP_NORM    75000   /* 75C */
  20 #define MLXSW_THERMAL_ASIC_TEMP_HIGH    85000   /* 85C */
  21 #define MLXSW_THERMAL_ASIC_TEMP_HOT     105000  /* 105C */
  22 #define MLXSW_THERMAL_ASIC_TEMP_CRIT    110000  /* 110C */
  23 #define MLXSW_THERMAL_HYSTERESIS_TEMP   5000    /* 5C */
  24 #define MLXSW_THERMAL_MODULE_TEMP_SHIFT (MLXSW_THERMAL_HYSTERESIS_TEMP * 2)
  25 #define MLXSW_THERMAL_ZONE_MAX_NAME     16
  26 #define MLXSW_THERMAL_TEMP_SCORE_MAX    GENMASK(31, 0)
  27 #define MLXSW_THERMAL_MAX_STATE 10
  28 #define MLXSW_THERMAL_MAX_DUTY  255
  29 /* Minimum and maximum fan allowed speed in percent: from 20% to 100%. Values
  30  * MLXSW_THERMAL_MAX_STATE + x, where x is between 2 and 10 are used for
  31  * setting fan speed dynamic minimum. For example, if value is set to 14 (40%)
  32  * cooling levels vector will be set to 4, 4, 4, 4, 4, 5, 6, 7, 8, 9, 10 to
  33  * introduce PWM speed in percent: 40, 40, 40, 40, 40, 50, 60. 70, 80, 90, 100.
  34  */
  35 #define MLXSW_THERMAL_SPEED_MIN         (MLXSW_THERMAL_MAX_STATE + 2)
  36 #define MLXSW_THERMAL_SPEED_MAX         (MLXSW_THERMAL_MAX_STATE * 2)
  37 #define MLXSW_THERMAL_SPEED_MIN_LEVEL   2               /* 20% */
  38 
  39 /* External cooling devices, allowed for binding to mlxsw thermal zones. */
  40 static char * const mlxsw_thermal_external_allowed_cdev[] = {
  41         "mlxreg_fan",
  42 };
  43 
  44 enum mlxsw_thermal_trips {
  45         MLXSW_THERMAL_TEMP_TRIP_NORM,
  46         MLXSW_THERMAL_TEMP_TRIP_HIGH,
  47         MLXSW_THERMAL_TEMP_TRIP_HOT,
  48         MLXSW_THERMAL_TEMP_TRIP_CRIT,
  49 };
  50 
  51 struct mlxsw_thermal_trip {
  52         int     type;
  53         int     temp;
  54         int     hyst;
  55         int     min_state;
  56         int     max_state;
  57 };
  58 
  59 static const struct mlxsw_thermal_trip default_thermal_trips[] = {
  60         {       /* In range - 0-40% PWM */
  61                 .type           = THERMAL_TRIP_ACTIVE,
  62                 .temp           = MLXSW_THERMAL_ASIC_TEMP_NORM,
  63                 .hyst           = MLXSW_THERMAL_HYSTERESIS_TEMP,
  64                 .min_state      = 0,
  65                 .max_state      = (4 * MLXSW_THERMAL_MAX_STATE) / 10,
  66         },
  67         {
  68                 /* In range - 40-100% PWM */
  69                 .type           = THERMAL_TRIP_ACTIVE,
  70                 .temp           = MLXSW_THERMAL_ASIC_TEMP_HIGH,
  71                 .hyst           = MLXSW_THERMAL_HYSTERESIS_TEMP,
  72                 .min_state      = (4 * MLXSW_THERMAL_MAX_STATE) / 10,
  73                 .max_state      = MLXSW_THERMAL_MAX_STATE,
  74         },
  75         {       /* Warning */
  76                 .type           = THERMAL_TRIP_HOT,
  77                 .temp           = MLXSW_THERMAL_ASIC_TEMP_HOT,
  78                 .hyst           = MLXSW_THERMAL_HYSTERESIS_TEMP,
  79                 .min_state      = MLXSW_THERMAL_MAX_STATE,
  80                 .max_state      = MLXSW_THERMAL_MAX_STATE,
  81         },
  82         {       /* Critical - soft poweroff */
  83                 .type           = THERMAL_TRIP_CRITICAL,
  84                 .temp           = MLXSW_THERMAL_ASIC_TEMP_CRIT,
  85                 .min_state      = MLXSW_THERMAL_MAX_STATE,
  86                 .max_state      = MLXSW_THERMAL_MAX_STATE,
  87         }
  88 };
  89 
  90 #define MLXSW_THERMAL_NUM_TRIPS ARRAY_SIZE(default_thermal_trips)
  91 
  92 /* Make sure all trips are writable */
  93 #define MLXSW_THERMAL_TRIP_MASK (BIT(MLXSW_THERMAL_NUM_TRIPS) - 1)
  94 
  95 struct mlxsw_thermal;
  96 
  97 struct mlxsw_thermal_module {
  98         struct mlxsw_thermal *parent;
  99         struct thermal_zone_device *tzdev;
 100         struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
 101         enum thermal_device_mode mode;
 102         int module; /* Module or gearbox number */
 103 };
 104 
 105 struct 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 
 121 static 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 
 127 static 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 
 133 static 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         /* Allow mlxsw thermal zone binding to an external cooling device */
 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 
 152 static void
 153 mlxsw_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 
 161 static int
 162 mlxsw_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         /* According to the system thermal requirements, the thermal zones are
 181          * defined with four trip points. The critical and emergency
 182          * temperature thresholds, provided by QSFP module are set as "active"
 183          * and "hot" trip points, "normal" and "critical" trip points are
 184          * derived from "active" and "hot" by subtracting or adding double
 185          * hysteresis value.
 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 
 203 static 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         /* Calculate thermal zone score, if temperature is above the critical
 212          * threshold score is set to MLXSW_THERMAL_TEMP_SCORE_MAX.
 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 
 231 static 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         /* If the cooling device is one of ours bind it */
 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 
 257 static 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         /* If the cooling device is our one unbind it */
 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 
 279 static 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 
 289 static 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 
 309 static 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 
 334 static 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 
 347 static 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 
 359 static 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 
 372 static 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 
 381 static 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 
 390 static int mlxsw_thermal_trend_get(struct thermal_zone_device *tzdev,
 391                                    int trip, enum thermal_trend *trend)
 392 {
 393         struct mlxsw_thermal *thermal = tzdev->devdata;
 394 
 395         if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
 396                 return -EINVAL;
 397 
 398         if (tzdev == thermal->tz_highest_dev)
 399                 return 1;
 400 
 401         *trend = THERMAL_TREND_STABLE;
 402         return 0;
 403 }
 404 
 405 static struct thermal_zone_device_ops mlxsw_thermal_ops = {
 406         .bind = mlxsw_thermal_bind,
 407         .unbind = mlxsw_thermal_unbind,
 408         .get_mode = mlxsw_thermal_get_mode,
 409         .set_mode = mlxsw_thermal_set_mode,
 410         .get_temp = mlxsw_thermal_get_temp,
 411         .get_trip_type  = mlxsw_thermal_get_trip_type,
 412         .get_trip_temp  = mlxsw_thermal_get_trip_temp,
 413         .set_trip_temp  = mlxsw_thermal_set_trip_temp,
 414         .get_trip_hyst  = mlxsw_thermal_get_trip_hyst,
 415         .set_trip_hyst  = mlxsw_thermal_set_trip_hyst,
 416         .get_trend      = mlxsw_thermal_trend_get,
 417 };
 418 
 419 static int mlxsw_thermal_module_bind(struct thermal_zone_device *tzdev,
 420                                      struct thermal_cooling_device *cdev)
 421 {
 422         struct mlxsw_thermal_module *tz = tzdev->devdata;
 423         struct mlxsw_thermal *thermal = tz->parent;
 424         int i, j, err;
 425 
 426         /* If the cooling device is one of ours bind it */
 427         if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0)
 428                 return 0;
 429 
 430         for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) {
 431                 const struct mlxsw_thermal_trip *trip = &tz->trips[i];
 432 
 433                 err = thermal_zone_bind_cooling_device(tzdev, i, cdev,
 434                                                        trip->max_state,
 435                                                        trip->min_state,
 436                                                        THERMAL_WEIGHT_DEFAULT);
 437                 if (err < 0)
 438                         goto err_bind_cooling_device;
 439         }
 440         return 0;
 441 
 442 err_bind_cooling_device:
 443         for (j = i - 1; j >= 0; j--)
 444                 thermal_zone_unbind_cooling_device(tzdev, j, cdev);
 445         return err;
 446 }
 447 
 448 static int mlxsw_thermal_module_unbind(struct thermal_zone_device *tzdev,
 449                                        struct thermal_cooling_device *cdev)
 450 {
 451         struct mlxsw_thermal_module *tz = tzdev->devdata;
 452         struct mlxsw_thermal *thermal = tz->parent;
 453         int i;
 454         int err;
 455 
 456         /* If the cooling device is one of ours unbind it */
 457         if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0)
 458                 return 0;
 459 
 460         for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) {
 461                 err = thermal_zone_unbind_cooling_device(tzdev, i, cdev);
 462                 WARN_ON(err);
 463         }
 464         return err;
 465 }
 466 
 467 static int mlxsw_thermal_module_mode_get(struct thermal_zone_device *tzdev,
 468                                          enum thermal_device_mode *mode)
 469 {
 470         struct mlxsw_thermal_module *tz = tzdev->devdata;
 471 
 472         *mode = tz->mode;
 473 
 474         return 0;
 475 }
 476 
 477 static int mlxsw_thermal_module_mode_set(struct thermal_zone_device *tzdev,
 478                                          enum thermal_device_mode mode)
 479 {
 480         struct mlxsw_thermal_module *tz = tzdev->devdata;
 481         struct mlxsw_thermal *thermal = tz->parent;
 482 
 483         mutex_lock(&tzdev->lock);
 484 
 485         if (mode == THERMAL_DEVICE_ENABLED)
 486                 tzdev->polling_delay = thermal->polling_delay;
 487         else
 488                 tzdev->polling_delay = 0;
 489 
 490         mutex_unlock(&tzdev->lock);
 491 
 492         tz->mode = mode;
 493         thermal_zone_device_update(tzdev, THERMAL_EVENT_UNSPECIFIED);
 494 
 495         return 0;
 496 }
 497 
 498 static int mlxsw_thermal_module_temp_get(struct thermal_zone_device *tzdev,
 499                                          int *p_temp)
 500 {
 501         struct mlxsw_thermal_module *tz = tzdev->devdata;
 502         struct mlxsw_thermal *thermal = tz->parent;
 503         struct device *dev = thermal->bus_info->dev;
 504         char mtmp_pl[MLXSW_REG_MTMP_LEN];
 505         int temp;
 506         int err;
 507 
 508         /* Read module temperature. */
 509         mlxsw_reg_mtmp_pack(mtmp_pl, MLXSW_REG_MTMP_MODULE_INDEX_MIN +
 510                             tz->module, false, false);
 511         err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl);
 512         if (err) {
 513                 /* Do not return error - in case of broken module's sensor
 514                  * it will cause error message flooding.
 515                  */
 516                 temp = 0;
 517                 *p_temp = (int) temp;
 518                 return 0;
 519         }
 520         mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL);
 521         *p_temp = temp;
 522 
 523         if (!temp)
 524                 return 0;
 525 
 526         /* Update trip points. */
 527         err = mlxsw_thermal_module_trips_update(dev, thermal->core, tz);
 528         if (!err && temp > 0)
 529                 mlxsw_thermal_tz_score_update(thermal, tzdev, tz->trips, temp);
 530 
 531         return 0;
 532 }
 533 
 534 static int
 535 mlxsw_thermal_module_trip_type_get(struct thermal_zone_device *tzdev, int trip,
 536                                    enum thermal_trip_type *p_type)
 537 {
 538         struct mlxsw_thermal_module *tz = tzdev->devdata;
 539 
 540         if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
 541                 return -EINVAL;
 542 
 543         *p_type = tz->trips[trip].type;
 544         return 0;
 545 }
 546 
 547 static int
 548 mlxsw_thermal_module_trip_temp_get(struct thermal_zone_device *tzdev,
 549                                    int trip, int *p_temp)
 550 {
 551         struct mlxsw_thermal_module *tz = tzdev->devdata;
 552 
 553         if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
 554                 return -EINVAL;
 555 
 556         *p_temp = tz->trips[trip].temp;
 557         return 0;
 558 }
 559 
 560 static int
 561 mlxsw_thermal_module_trip_temp_set(struct thermal_zone_device *tzdev,
 562                                    int trip, int temp)
 563 {
 564         struct mlxsw_thermal_module *tz = tzdev->devdata;
 565 
 566         if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS ||
 567             temp > tz->trips[MLXSW_THERMAL_TEMP_TRIP_CRIT].temp)
 568                 return -EINVAL;
 569 
 570         tz->trips[trip].temp = temp;
 571         return 0;
 572 }
 573 
 574 static int
 575 mlxsw_thermal_module_trip_hyst_get(struct thermal_zone_device *tzdev, int trip,
 576                                    int *p_hyst)
 577 {
 578         struct mlxsw_thermal_module *tz = tzdev->devdata;
 579 
 580         *p_hyst = tz->trips[trip].hyst;
 581         return 0;
 582 }
 583 
 584 static int
 585 mlxsw_thermal_module_trip_hyst_set(struct thermal_zone_device *tzdev, int trip,
 586                                    int hyst)
 587 {
 588         struct mlxsw_thermal_module *tz = tzdev->devdata;
 589 
 590         tz->trips[trip].hyst = hyst;
 591         return 0;
 592 }
 593 
 594 static int mlxsw_thermal_module_trend_get(struct thermal_zone_device *tzdev,
 595                                           int trip, enum thermal_trend *trend)
 596 {
 597         struct mlxsw_thermal_module *tz = tzdev->devdata;
 598         struct mlxsw_thermal *thermal = tz->parent;
 599 
 600         if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
 601                 return -EINVAL;
 602 
 603         if (tzdev == thermal->tz_highest_dev)
 604                 return 1;
 605 
 606         *trend = THERMAL_TREND_STABLE;
 607         return 0;
 608 }
 609 
 610 static struct thermal_zone_device_ops mlxsw_thermal_module_ops = {
 611         .bind           = mlxsw_thermal_module_bind,
 612         .unbind         = mlxsw_thermal_module_unbind,
 613         .get_mode       = mlxsw_thermal_module_mode_get,
 614         .set_mode       = mlxsw_thermal_module_mode_set,
 615         .get_temp       = mlxsw_thermal_module_temp_get,
 616         .get_trip_type  = mlxsw_thermal_module_trip_type_get,
 617         .get_trip_temp  = mlxsw_thermal_module_trip_temp_get,
 618         .set_trip_temp  = mlxsw_thermal_module_trip_temp_set,
 619         .get_trip_hyst  = mlxsw_thermal_module_trip_hyst_get,
 620         .set_trip_hyst  = mlxsw_thermal_module_trip_hyst_set,
 621         .get_trend      = mlxsw_thermal_module_trend_get,
 622 };
 623 
 624 static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev,
 625                                           int *p_temp)
 626 {
 627         struct mlxsw_thermal_module *tz = tzdev->devdata;
 628         struct mlxsw_thermal *thermal = tz->parent;
 629         char mtmp_pl[MLXSW_REG_MTMP_LEN];
 630         u16 index;
 631         int temp;
 632         int err;
 633 
 634         index = MLXSW_REG_MTMP_GBOX_INDEX_MIN + tz->module;
 635         mlxsw_reg_mtmp_pack(mtmp_pl, index, false, false);
 636 
 637         err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl);
 638         if (err)
 639                 return err;
 640 
 641         mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL);
 642         if (temp > 0)
 643                 mlxsw_thermal_tz_score_update(thermal, tzdev, tz->trips, temp);
 644 
 645         *p_temp = temp;
 646         return 0;
 647 }
 648 
 649 static struct thermal_zone_device_ops mlxsw_thermal_gearbox_ops = {
 650         .bind           = mlxsw_thermal_module_bind,
 651         .unbind         = mlxsw_thermal_module_unbind,
 652         .get_mode       = mlxsw_thermal_module_mode_get,
 653         .set_mode       = mlxsw_thermal_module_mode_set,
 654         .get_temp       = mlxsw_thermal_gearbox_temp_get,
 655         .get_trip_type  = mlxsw_thermal_module_trip_type_get,
 656         .get_trip_temp  = mlxsw_thermal_module_trip_temp_get,
 657         .set_trip_temp  = mlxsw_thermal_module_trip_temp_set,
 658         .get_trip_hyst  = mlxsw_thermal_module_trip_hyst_get,
 659         .set_trip_hyst  = mlxsw_thermal_module_trip_hyst_set,
 660         .get_trend      = mlxsw_thermal_module_trend_get,
 661 };
 662 
 663 static int mlxsw_thermal_get_max_state(struct thermal_cooling_device *cdev,
 664                                        unsigned long *p_state)
 665 {
 666         *p_state = MLXSW_THERMAL_MAX_STATE;
 667         return 0;
 668 }
 669 
 670 static int mlxsw_thermal_get_cur_state(struct thermal_cooling_device *cdev,
 671                                        unsigned long *p_state)
 672 
 673 {
 674         struct mlxsw_thermal *thermal = cdev->devdata;
 675         struct device *dev = thermal->bus_info->dev;
 676         char mfsc_pl[MLXSW_REG_MFSC_LEN];
 677         int err, idx;
 678         u8 duty;
 679 
 680         idx = mlxsw_get_cooling_device_idx(thermal, cdev);
 681         if (idx < 0)
 682                 return idx;
 683 
 684         mlxsw_reg_mfsc_pack(mfsc_pl, idx, 0);
 685         err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfsc), mfsc_pl);
 686         if (err) {
 687                 dev_err(dev, "Failed to query PWM duty\n");
 688                 return err;
 689         }
 690 
 691         duty = mlxsw_reg_mfsc_pwm_duty_cycle_get(mfsc_pl);
 692         *p_state = mlxsw_duty_to_state(duty);
 693         return 0;
 694 }
 695 
 696 static int mlxsw_thermal_set_cur_state(struct thermal_cooling_device *cdev,
 697                                        unsigned long state)
 698 
 699 {
 700         struct mlxsw_thermal *thermal = cdev->devdata;
 701         struct device *dev = thermal->bus_info->dev;
 702         char mfsc_pl[MLXSW_REG_MFSC_LEN];
 703         unsigned long cur_state, i;
 704         int idx;
 705         u8 duty;
 706         int err;
 707 
 708         idx = mlxsw_get_cooling_device_idx(thermal, cdev);
 709         if (idx < 0)
 710                 return idx;
 711 
 712         /* Verify if this request is for changing allowed fan dynamical
 713          * minimum. If it is - update cooling levels accordingly and update
 714          * state, if current state is below the newly requested minimum state.
 715          * For example, if current state is 5, and minimal state is to be
 716          * changed from 4 to 6, thermal->cooling_levels[0 to 5] will be changed
 717          * all from 4 to 6. And state 5 (thermal->cooling_levels[4]) should be
 718          * overwritten.
 719          */
 720         if (state >= MLXSW_THERMAL_SPEED_MIN &&
 721             state <= MLXSW_THERMAL_SPEED_MAX) {
 722                 state -= MLXSW_THERMAL_MAX_STATE;
 723                 for (i = 0; i <= MLXSW_THERMAL_MAX_STATE; i++)
 724                         thermal->cooling_levels[i] = max(state, i);
 725 
 726                 mlxsw_reg_mfsc_pack(mfsc_pl, idx, 0);
 727                 err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfsc), mfsc_pl);
 728                 if (err)
 729                         return err;
 730 
 731                 duty = mlxsw_reg_mfsc_pwm_duty_cycle_get(mfsc_pl);
 732                 cur_state = mlxsw_duty_to_state(duty);
 733 
 734                 /* If current fan state is lower than requested dynamical
 735                  * minimum, increase fan speed up to dynamical minimum.
 736                  */
 737                 if (state < cur_state)
 738                         return 0;
 739 
 740                 state = cur_state;
 741         }
 742 
 743         if (state > MLXSW_THERMAL_MAX_STATE)
 744                 return -EINVAL;
 745 
 746         /* Normalize the state to the valid speed range. */
 747         state = thermal->cooling_levels[state];
 748         mlxsw_reg_mfsc_pack(mfsc_pl, idx, mlxsw_state_to_duty(state));
 749         err = mlxsw_reg_write(thermal->core, MLXSW_REG(mfsc), mfsc_pl);
 750         if (err) {
 751                 dev_err(dev, "Failed to write PWM duty\n");
 752                 return err;
 753         }
 754         return 0;
 755 }
 756 
 757 static const struct thermal_cooling_device_ops mlxsw_cooling_ops = {
 758         .get_max_state  = mlxsw_thermal_get_max_state,
 759         .get_cur_state  = mlxsw_thermal_get_cur_state,
 760         .set_cur_state  = mlxsw_thermal_set_cur_state,
 761 };
 762 
 763 static int
 764 mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz)
 765 {
 766         char tz_name[MLXSW_THERMAL_ZONE_MAX_NAME];
 767         int err;
 768 
 769         snprintf(tz_name, sizeof(tz_name), "mlxsw-module%d",
 770                  module_tz->module + 1);
 771         module_tz->tzdev = thermal_zone_device_register(tz_name,
 772                                                         MLXSW_THERMAL_NUM_TRIPS,
 773                                                         MLXSW_THERMAL_TRIP_MASK,
 774                                                         module_tz,
 775                                                         &mlxsw_thermal_module_ops,
 776                                                         NULL, 0, 0);
 777         if (IS_ERR(module_tz->tzdev)) {
 778                 err = PTR_ERR(module_tz->tzdev);
 779                 return err;
 780         }
 781 
 782         module_tz->mode = THERMAL_DEVICE_ENABLED;
 783         return 0;
 784 }
 785 
 786 static void mlxsw_thermal_module_tz_fini(struct thermal_zone_device *tzdev)
 787 {
 788         thermal_zone_device_unregister(tzdev);
 789 }
 790 
 791 static int
 792 mlxsw_thermal_module_init(struct device *dev, struct mlxsw_core *core,
 793                           struct mlxsw_thermal *thermal, u8 local_port)
 794 {
 795         struct mlxsw_thermal_module *module_tz;
 796         char pmlp_pl[MLXSW_REG_PMLP_LEN];
 797         u8 width, module;
 798         int err;
 799 
 800         mlxsw_reg_pmlp_pack(pmlp_pl, local_port);
 801         err = mlxsw_reg_query(core, MLXSW_REG(pmlp), pmlp_pl);
 802         if (err)
 803                 return err;
 804 
 805         width = mlxsw_reg_pmlp_width_get(pmlp_pl);
 806         if (!width)
 807                 return 0;
 808 
 809         module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0);
 810         module_tz = &thermal->tz_module_arr[module];
 811         /* Skip if parent is already set (case of port split). */
 812         if (module_tz->parent)
 813                 return 0;
 814         module_tz->module = module;
 815         module_tz->parent = thermal;
 816         memcpy(module_tz->trips, default_thermal_trips,
 817                sizeof(thermal->trips));
 818         /* Initialize all trip point. */
 819         mlxsw_thermal_module_trips_reset(module_tz);
 820         /* Update trip point according to the module data. */
 821         return mlxsw_thermal_module_trips_update(dev, core, module_tz);
 822 }
 823 
 824 static void mlxsw_thermal_module_fini(struct mlxsw_thermal_module *module_tz)
 825 {
 826         if (module_tz && module_tz->tzdev) {
 827                 mlxsw_thermal_module_tz_fini(module_tz->tzdev);
 828                 module_tz->tzdev = NULL;
 829                 module_tz->parent = NULL;
 830         }
 831 }
 832 
 833 static int
 834 mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core,
 835                            struct mlxsw_thermal *thermal)
 836 {
 837         unsigned int module_count = mlxsw_core_max_ports(core);
 838         struct mlxsw_thermal_module *module_tz;
 839         int i, err;
 840 
 841         if (!mlxsw_core_res_query_enabled(core))
 842                 return 0;
 843 
 844         thermal->tz_module_arr = kcalloc(module_count,
 845                                          sizeof(*thermal->tz_module_arr),
 846                                          GFP_KERNEL);
 847         if (!thermal->tz_module_arr)
 848                 return -ENOMEM;
 849 
 850         for (i = 1; i < module_count; i++) {
 851                 err = mlxsw_thermal_module_init(dev, core, thermal, i);
 852                 if (err)
 853                         goto err_unreg_tz_module_arr;
 854         }
 855 
 856         for (i = 0; i < module_count - 1; i++) {
 857                 module_tz = &thermal->tz_module_arr[i];
 858                 if (!module_tz->parent)
 859                         continue;
 860                 err = mlxsw_thermal_module_tz_init(module_tz);
 861                 if (err)
 862                         goto err_unreg_tz_module_arr;
 863         }
 864 
 865         return 0;
 866 
 867 err_unreg_tz_module_arr:
 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         return err;
 872 }
 873 
 874 static void
 875 mlxsw_thermal_modules_fini(struct mlxsw_thermal *thermal)
 876 {
 877         unsigned int module_count = mlxsw_core_max_ports(thermal->core);
 878         int i;
 879 
 880         if (!mlxsw_core_res_query_enabled(thermal->core))
 881                 return;
 882 
 883         for (i = module_count - 1; i >= 0; i--)
 884                 mlxsw_thermal_module_fini(&thermal->tz_module_arr[i]);
 885         kfree(thermal->tz_module_arr);
 886 }
 887 
 888 static int
 889 mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz)
 890 {
 891         char tz_name[MLXSW_THERMAL_ZONE_MAX_NAME];
 892 
 893         snprintf(tz_name, sizeof(tz_name), "mlxsw-gearbox%d",
 894                  gearbox_tz->module + 1);
 895         gearbox_tz->tzdev = thermal_zone_device_register(tz_name,
 896                                                 MLXSW_THERMAL_NUM_TRIPS,
 897                                                 MLXSW_THERMAL_TRIP_MASK,
 898                                                 gearbox_tz,
 899                                                 &mlxsw_thermal_gearbox_ops,
 900                                                 NULL, 0, 0);
 901         if (IS_ERR(gearbox_tz->tzdev))
 902                 return PTR_ERR(gearbox_tz->tzdev);
 903 
 904         gearbox_tz->mode = THERMAL_DEVICE_ENABLED;
 905         return 0;
 906 }
 907 
 908 static void
 909 mlxsw_thermal_gearbox_tz_fini(struct mlxsw_thermal_module *gearbox_tz)
 910 {
 911         thermal_zone_device_unregister(gearbox_tz->tzdev);
 912 }
 913 
 914 static int
 915 mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core,
 916                              struct mlxsw_thermal *thermal)
 917 {
 918         struct mlxsw_thermal_module *gearbox_tz;
 919         char mgpir_pl[MLXSW_REG_MGPIR_LEN];
 920         int i;
 921         int err;
 922 
 923         if (!mlxsw_core_res_query_enabled(core))
 924                 return 0;
 925 
 926         mlxsw_reg_mgpir_pack(mgpir_pl);
 927         err = mlxsw_reg_query(core, MLXSW_REG(mgpir), mgpir_pl);
 928         if (err)
 929                 return err;
 930 
 931         mlxsw_reg_mgpir_unpack(mgpir_pl, &thermal->tz_gearbox_num, NULL, NULL);
 932         if (!thermal->tz_gearbox_num)
 933                 return 0;
 934 
 935         thermal->tz_gearbox_arr = kcalloc(thermal->tz_gearbox_num,
 936                                           sizeof(*thermal->tz_gearbox_arr),
 937                                           GFP_KERNEL);
 938         if (!thermal->tz_gearbox_arr)
 939                 return -ENOMEM;
 940 
 941         for (i = 0; i < thermal->tz_gearbox_num; i++) {
 942                 gearbox_tz = &thermal->tz_gearbox_arr[i];
 943                 memcpy(gearbox_tz->trips, default_thermal_trips,
 944                        sizeof(thermal->trips));
 945                 gearbox_tz->module = i;
 946                 gearbox_tz->parent = thermal;
 947                 err = mlxsw_thermal_gearbox_tz_init(gearbox_tz);
 948                 if (err)
 949                         goto err_unreg_tz_gearbox;
 950         }
 951 
 952         return 0;
 953 
 954 err_unreg_tz_gearbox:
 955         for (i--; i >= 0; i--)
 956                 mlxsw_thermal_gearbox_tz_fini(&thermal->tz_gearbox_arr[i]);
 957         kfree(thermal->tz_gearbox_arr);
 958         return err;
 959 }
 960 
 961 static void
 962 mlxsw_thermal_gearboxes_fini(struct mlxsw_thermal *thermal)
 963 {
 964         int i;
 965 
 966         if (!mlxsw_core_res_query_enabled(thermal->core))
 967                 return;
 968 
 969         for (i = thermal->tz_gearbox_num - 1; i >= 0; i--)
 970                 mlxsw_thermal_gearbox_tz_fini(&thermal->tz_gearbox_arr[i]);
 971         kfree(thermal->tz_gearbox_arr);
 972 }
 973 
 974 int mlxsw_thermal_init(struct mlxsw_core *core,
 975                        const struct mlxsw_bus_info *bus_info,
 976                        struct mlxsw_thermal **p_thermal)
 977 {
 978         char mfcr_pl[MLXSW_REG_MFCR_LEN] = { 0 };
 979         enum mlxsw_reg_mfcr_pwm_frequency freq;
 980         struct device *dev = bus_info->dev;
 981         struct mlxsw_thermal *thermal;
 982         u16 tacho_active;
 983         u8 pwm_active;
 984         int err, i;
 985 
 986         thermal = devm_kzalloc(dev, sizeof(*thermal),
 987                                GFP_KERNEL);
 988         if (!thermal)
 989                 return -ENOMEM;
 990 
 991         thermal->core = core;
 992         thermal->bus_info = bus_info;
 993         memcpy(thermal->trips, default_thermal_trips, sizeof(thermal->trips));
 994 
 995         err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfcr), mfcr_pl);
 996         if (err) {
 997                 dev_err(dev, "Failed to probe PWMs\n");
 998                 goto err_free_thermal;
 999         }
1000         mlxsw_reg_mfcr_unpack(mfcr_pl, &freq, &tacho_active, &pwm_active);
1001 
1002         for (i = 0; i < MLXSW_MFCR_TACHOS_MAX; i++) {
1003                 if (tacho_active & BIT(i)) {
1004                         char mfsl_pl[MLXSW_REG_MFSL_LEN];
1005 
1006                         mlxsw_reg_mfsl_pack(mfsl_pl, i, 0, 0);
1007 
1008                         /* We need to query the register to preserve maximum */
1009                         err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfsl),
1010                                               mfsl_pl);
1011                         if (err)
1012                                 goto err_free_thermal;
1013 
1014                         /* set the minimal RPMs to 0 */
1015                         mlxsw_reg_mfsl_tach_min_set(mfsl_pl, 0);
1016                         err = mlxsw_reg_write(thermal->core, MLXSW_REG(mfsl),
1017                                               mfsl_pl);
1018                         if (err)
1019                                 goto err_free_thermal;
1020                 }
1021         }
1022         for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++) {
1023                 if (pwm_active & BIT(i)) {
1024                         struct thermal_cooling_device *cdev;
1025 
1026                         cdev = thermal_cooling_device_register("mlxsw_fan",
1027                                                                thermal,
1028                                                                &mlxsw_cooling_ops);
1029                         if (IS_ERR(cdev)) {
1030                                 err = PTR_ERR(cdev);
1031                                 dev_err(dev, "Failed to register cooling device\n");
1032                                 goto err_unreg_cdevs;
1033                         }
1034                         thermal->cdevs[i] = cdev;
1035                 }
1036         }
1037 
1038         /* Initialize cooling levels per PWM state. */
1039         for (i = 0; i < MLXSW_THERMAL_MAX_STATE; i++)
1040                 thermal->cooling_levels[i] = max(MLXSW_THERMAL_SPEED_MIN_LEVEL,
1041                                                  i);
1042 
1043         thermal->polling_delay = bus_info->low_frequency ?
1044                                  MLXSW_THERMAL_SLOW_POLL_INT :
1045                                  MLXSW_THERMAL_POLL_INT;
1046 
1047         thermal->tzdev = thermal_zone_device_register("mlxsw",
1048                                                       MLXSW_THERMAL_NUM_TRIPS,
1049                                                       MLXSW_THERMAL_TRIP_MASK,
1050                                                       thermal,
1051                                                       &mlxsw_thermal_ops,
1052                                                       NULL, 0,
1053                                                       thermal->polling_delay);
1054         if (IS_ERR(thermal->tzdev)) {
1055                 err = PTR_ERR(thermal->tzdev);
1056                 dev_err(dev, "Failed to register thermal zone\n");
1057                 goto err_unreg_cdevs;
1058         }
1059 
1060         err = mlxsw_thermal_modules_init(dev, core, thermal);
1061         if (err)
1062                 goto err_unreg_tzdev;
1063 
1064         err = mlxsw_thermal_gearboxes_init(dev, core, thermal);
1065         if (err)
1066                 goto err_unreg_modules_tzdev;
1067 
1068         thermal->mode = THERMAL_DEVICE_ENABLED;
1069         *p_thermal = thermal;
1070         return 0;
1071 
1072 err_unreg_modules_tzdev:
1073         mlxsw_thermal_modules_fini(thermal);
1074 err_unreg_tzdev:
1075         if (thermal->tzdev) {
1076                 thermal_zone_device_unregister(thermal->tzdev);
1077                 thermal->tzdev = NULL;
1078         }
1079 err_unreg_cdevs:
1080         for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++)
1081                 if (thermal->cdevs[i])
1082                         thermal_cooling_device_unregister(thermal->cdevs[i]);
1083 err_free_thermal:
1084         devm_kfree(dev, thermal);
1085         return err;
1086 }
1087 
1088 void mlxsw_thermal_fini(struct mlxsw_thermal *thermal)
1089 {
1090         int i;
1091 
1092         mlxsw_thermal_gearboxes_fini(thermal);
1093         mlxsw_thermal_modules_fini(thermal);
1094         if (thermal->tzdev) {
1095                 thermal_zone_device_unregister(thermal->tzdev);
1096                 thermal->tzdev = NULL;
1097         }
1098 
1099         for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++) {
1100                 if (thermal->cdevs[i]) {
1101                         thermal_cooling_device_unregister(thermal->cdevs[i]);
1102                         thermal->cdevs[i] = NULL;
1103                 }
1104         }
1105 
1106         devm_kfree(thermal->bus_info->dev, thermal);
1107 }

/* [<][>][^][v][top][bottom][index][help] */