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