linux/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
<<
>>
Prefs
   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. */
  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        {       /* 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
  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; /* Module or gearbox number */
 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        /* 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
 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        /* 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
 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        /* 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
 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        /* 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
 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        /* 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
 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        /* If the cooling device is one of ours bind it */
 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        /* If the cooling device is one of ours unbind it */
 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        /* Read module temperature. */
 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                /* Do not return error - in case of broken module's sensor
 515                 * it will cause error message flooding.
 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        /* Update trip points. */
 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        /* Verify if this request is for changing allowed fan dynamical
 698         * minimum. If it is - update cooling levels accordingly and update
 699         * state, if current state is below the newly requested minimum state.
 700         * For example, if current state is 5, and minimal state is to be
 701         * changed from 4 to 6, thermal->cooling_levels[0 to 5] will be changed
 702         * all from 4 to 6. And state 5 (thermal->cooling_levels[4]) should be
 703         * overwritten.
 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                /* If current fan state is lower than requested dynamical
 720                 * minimum, increase fan speed up to dynamical minimum.
 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        /* Normalize the state to the valid speed range. */
 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        /* Skip if parent is already set (case of port split). */
 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        /* Initialize all trip point. */
 804        mlxsw_thermal_module_trips_reset(module_tz);
 805        /* Update trip point according to the module data. */
 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                        /* We need to query the register to preserve maximum */
 994                        err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfsl),
 995                                              mfsl_pl);
 996                        if (err)
 997                                goto err_free_thermal;
 998
 999                        /* set the minimal RPMs to 0 */
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        /* Initialize cooling levels per PWM state. */
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