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