Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /* Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved
0003  * Copyright (c) 2016 Ivan Vecera <cera@cera.cz>
0004  */
0005 
0006 #include <linux/kernel.h>
0007 #include <linux/types.h>
0008 #include <linux/device.h>
0009 #include <linux/sysfs.h>
0010 #include <linux/thermal.h>
0011 #include <linux/err.h>
0012 #include <linux/sfp.h>
0013 
0014 #include "core.h"
0015 #include "core_env.h"
0016 
0017 #define MLXSW_THERMAL_POLL_INT  1000    /* ms */
0018 #define MLXSW_THERMAL_SLOW_POLL_INT 20000   /* ms */
0019 #define MLXSW_THERMAL_ASIC_TEMP_NORM    75000   /* 75C */
0020 #define MLXSW_THERMAL_ASIC_TEMP_HIGH    85000   /* 85C */
0021 #define MLXSW_THERMAL_ASIC_TEMP_HOT 105000  /* 105C */
0022 #define MLXSW_THERMAL_HYSTERESIS_TEMP   5000    /* 5C */
0023 #define MLXSW_THERMAL_MODULE_TEMP_SHIFT (MLXSW_THERMAL_HYSTERESIS_TEMP * 2)
0024 #define MLXSW_THERMAL_TEMP_SCORE_MAX    GENMASK(31, 0)
0025 #define MLXSW_THERMAL_MAX_STATE 10
0026 #define MLXSW_THERMAL_MIN_STATE 2
0027 #define MLXSW_THERMAL_MAX_DUTY  255
0028 
0029 /* External cooling devices, allowed for binding to mlxsw thermal zones. */
0030 static char * const mlxsw_thermal_external_allowed_cdev[] = {
0031     "mlxreg_fan",
0032 };
0033 
0034 enum mlxsw_thermal_trips {
0035     MLXSW_THERMAL_TEMP_TRIP_NORM,
0036     MLXSW_THERMAL_TEMP_TRIP_HIGH,
0037     MLXSW_THERMAL_TEMP_TRIP_HOT,
0038 };
0039 
0040 struct mlxsw_thermal_trip {
0041     int type;
0042     int temp;
0043     int hyst;
0044     int min_state;
0045     int max_state;
0046 };
0047 
0048 static const struct mlxsw_thermal_trip default_thermal_trips[] = {
0049     {   /* In range - 0-40% PWM */
0050         .type       = THERMAL_TRIP_ACTIVE,
0051         .temp       = MLXSW_THERMAL_ASIC_TEMP_NORM,
0052         .hyst       = MLXSW_THERMAL_HYSTERESIS_TEMP,
0053         .min_state  = 0,
0054         .max_state  = (4 * MLXSW_THERMAL_MAX_STATE) / 10,
0055     },
0056     {
0057         /* In range - 40-100% PWM */
0058         .type       = THERMAL_TRIP_ACTIVE,
0059         .temp       = MLXSW_THERMAL_ASIC_TEMP_HIGH,
0060         .hyst       = MLXSW_THERMAL_HYSTERESIS_TEMP,
0061         .min_state  = (4 * MLXSW_THERMAL_MAX_STATE) / 10,
0062         .max_state  = MLXSW_THERMAL_MAX_STATE,
0063     },
0064     {   /* Warning */
0065         .type       = THERMAL_TRIP_HOT,
0066         .temp       = MLXSW_THERMAL_ASIC_TEMP_HOT,
0067         .min_state  = MLXSW_THERMAL_MAX_STATE,
0068         .max_state  = MLXSW_THERMAL_MAX_STATE,
0069     },
0070 };
0071 
0072 #define MLXSW_THERMAL_NUM_TRIPS ARRAY_SIZE(default_thermal_trips)
0073 
0074 /* Make sure all trips are writable */
0075 #define MLXSW_THERMAL_TRIP_MASK (BIT(MLXSW_THERMAL_NUM_TRIPS) - 1)
0076 
0077 struct mlxsw_thermal;
0078 
0079 struct mlxsw_thermal_module {
0080     struct mlxsw_thermal *parent;
0081     struct thermal_zone_device *tzdev;
0082     struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
0083     int module; /* Module or gearbox number */
0084     u8 slot_index;
0085 };
0086 
0087 struct mlxsw_thermal_area {
0088     struct mlxsw_thermal_module *tz_module_arr;
0089     u8 tz_module_num;
0090     struct mlxsw_thermal_module *tz_gearbox_arr;
0091     u8 tz_gearbox_num;
0092     u8 slot_index;
0093     bool active;
0094 };
0095 
0096 struct mlxsw_thermal {
0097     struct mlxsw_core *core;
0098     const struct mlxsw_bus_info *bus_info;
0099     struct thermal_zone_device *tzdev;
0100     int polling_delay;
0101     struct thermal_cooling_device *cdevs[MLXSW_MFCR_PWMS_MAX];
0102     u8 cooling_levels[MLXSW_THERMAL_MAX_STATE + 1];
0103     struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
0104     unsigned int tz_highest_score;
0105     struct thermal_zone_device *tz_highest_dev;
0106     struct mlxsw_thermal_area line_cards[];
0107 };
0108 
0109 static inline u8 mlxsw_state_to_duty(int state)
0110 {
0111     return DIV_ROUND_CLOSEST(state * MLXSW_THERMAL_MAX_DUTY,
0112                  MLXSW_THERMAL_MAX_STATE);
0113 }
0114 
0115 static inline int mlxsw_duty_to_state(u8 duty)
0116 {
0117     return DIV_ROUND_CLOSEST(duty * MLXSW_THERMAL_MAX_STATE,
0118                  MLXSW_THERMAL_MAX_DUTY);
0119 }
0120 
0121 static int mlxsw_get_cooling_device_idx(struct mlxsw_thermal *thermal,
0122                     struct thermal_cooling_device *cdev)
0123 {
0124     int i;
0125 
0126     for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++)
0127         if (thermal->cdevs[i] == cdev)
0128             return i;
0129 
0130     /* Allow mlxsw thermal zone binding to an external cooling device */
0131     for (i = 0; i < ARRAY_SIZE(mlxsw_thermal_external_allowed_cdev); i++) {
0132         if (!strcmp(cdev->type, mlxsw_thermal_external_allowed_cdev[i]))
0133             return 0;
0134     }
0135 
0136     return -ENODEV;
0137 }
0138 
0139 static void
0140 mlxsw_thermal_module_trips_reset(struct mlxsw_thermal_module *tz)
0141 {
0142     tz->trips[MLXSW_THERMAL_TEMP_TRIP_NORM].temp = 0;
0143     tz->trips[MLXSW_THERMAL_TEMP_TRIP_HIGH].temp = 0;
0144     tz->trips[MLXSW_THERMAL_TEMP_TRIP_HOT].temp = 0;
0145 }
0146 
0147 static int
0148 mlxsw_thermal_module_trips_update(struct device *dev, struct mlxsw_core *core,
0149                   struct mlxsw_thermal_module *tz,
0150                   int crit_temp, int emerg_temp)
0151 {
0152     int err;
0153 
0154     /* Do not try to query temperature thresholds directly from the module's
0155      * EEPROM if we got valid thresholds from MTMP.
0156      */
0157     if (!emerg_temp || !crit_temp) {
0158         err = mlxsw_env_module_temp_thresholds_get(core, tz->slot_index,
0159                                tz->module,
0160                                SFP_TEMP_HIGH_WARN,
0161                                &crit_temp);
0162         if (err)
0163             return err;
0164 
0165         err = mlxsw_env_module_temp_thresholds_get(core, tz->slot_index,
0166                                tz->module,
0167                                SFP_TEMP_HIGH_ALARM,
0168                                &emerg_temp);
0169         if (err)
0170             return err;
0171     }
0172 
0173     if (crit_temp > emerg_temp) {
0174         dev_warn(dev, "%s : Critical threshold %d is above emergency threshold %d\n",
0175              tz->tzdev->type, crit_temp, emerg_temp);
0176         return 0;
0177     }
0178 
0179     /* According to the system thermal requirements, the thermal zones are
0180      * defined with three trip points. The critical and emergency
0181      * temperature thresholds, provided by QSFP module are set as "active"
0182      * and "hot" trip points, "normal" trip point is derived from "active"
0183      * by subtracting double hysteresis value.
0184      */
0185     if (crit_temp >= MLXSW_THERMAL_MODULE_TEMP_SHIFT)
0186         tz->trips[MLXSW_THERMAL_TEMP_TRIP_NORM].temp = crit_temp -
0187                     MLXSW_THERMAL_MODULE_TEMP_SHIFT;
0188     else
0189         tz->trips[MLXSW_THERMAL_TEMP_TRIP_NORM].temp = crit_temp;
0190     tz->trips[MLXSW_THERMAL_TEMP_TRIP_HIGH].temp = crit_temp;
0191     tz->trips[MLXSW_THERMAL_TEMP_TRIP_HOT].temp = emerg_temp;
0192 
0193     return 0;
0194 }
0195 
0196 static void mlxsw_thermal_tz_score_update(struct mlxsw_thermal *thermal,
0197                       struct thermal_zone_device *tzdev,
0198                       struct mlxsw_thermal_trip *trips,
0199                       int temp)
0200 {
0201     struct mlxsw_thermal_trip *trip = trips;
0202     unsigned int score, delta, i, shift = 1;
0203 
0204     /* Calculate thermal zone score, if temperature is above the hot
0205      * threshold score is set to MLXSW_THERMAL_TEMP_SCORE_MAX.
0206      */
0207     score = MLXSW_THERMAL_TEMP_SCORE_MAX;
0208     for (i = MLXSW_THERMAL_TEMP_TRIP_NORM; i < MLXSW_THERMAL_NUM_TRIPS;
0209          i++, trip++) {
0210         if (temp < trip->temp) {
0211             delta = DIV_ROUND_CLOSEST(temp, trip->temp - temp);
0212             score = delta * shift;
0213             break;
0214         }
0215         shift *= 256;
0216     }
0217 
0218     if (score > thermal->tz_highest_score) {
0219         thermal->tz_highest_score = score;
0220         thermal->tz_highest_dev = tzdev;
0221     }
0222 }
0223 
0224 static int mlxsw_thermal_bind(struct thermal_zone_device *tzdev,
0225                   struct thermal_cooling_device *cdev)
0226 {
0227     struct mlxsw_thermal *thermal = tzdev->devdata;
0228     struct device *dev = thermal->bus_info->dev;
0229     int i, err;
0230 
0231     /* If the cooling device is one of ours bind it */
0232     if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0)
0233         return 0;
0234 
0235     for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) {
0236         const struct mlxsw_thermal_trip *trip = &thermal->trips[i];
0237 
0238         err = thermal_zone_bind_cooling_device(tzdev, i, cdev,
0239                                trip->max_state,
0240                                trip->min_state,
0241                                THERMAL_WEIGHT_DEFAULT);
0242         if (err < 0) {
0243             dev_err(dev, "Failed to bind cooling device to trip %d\n", i);
0244             return err;
0245         }
0246     }
0247     return 0;
0248 }
0249 
0250 static int mlxsw_thermal_unbind(struct thermal_zone_device *tzdev,
0251                 struct thermal_cooling_device *cdev)
0252 {
0253     struct mlxsw_thermal *thermal = tzdev->devdata;
0254     struct device *dev = thermal->bus_info->dev;
0255     int i;
0256     int err;
0257 
0258     /* If the cooling device is our one unbind it */
0259     if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0)
0260         return 0;
0261 
0262     for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) {
0263         err = thermal_zone_unbind_cooling_device(tzdev, i, cdev);
0264         if (err < 0) {
0265             dev_err(dev, "Failed to unbind cooling device\n");
0266             return err;
0267         }
0268     }
0269     return 0;
0270 }
0271 
0272 static int mlxsw_thermal_get_temp(struct thermal_zone_device *tzdev,
0273                   int *p_temp)
0274 {
0275     struct mlxsw_thermal *thermal = tzdev->devdata;
0276     struct device *dev = thermal->bus_info->dev;
0277     char mtmp_pl[MLXSW_REG_MTMP_LEN];
0278     int temp;
0279     int err;
0280 
0281     mlxsw_reg_mtmp_pack(mtmp_pl, 0, 0, false, false);
0282 
0283     err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl);
0284     if (err) {
0285         dev_err(dev, "Failed to query temp sensor\n");
0286         return err;
0287     }
0288     mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL, NULL, NULL);
0289     if (temp > 0)
0290         mlxsw_thermal_tz_score_update(thermal, tzdev, thermal->trips,
0291                           temp);
0292 
0293     *p_temp = temp;
0294     return 0;
0295 }
0296 
0297 static int mlxsw_thermal_get_trip_type(struct thermal_zone_device *tzdev,
0298                        int trip,
0299                        enum thermal_trip_type *p_type)
0300 {
0301     struct mlxsw_thermal *thermal = tzdev->devdata;
0302 
0303     if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
0304         return -EINVAL;
0305 
0306     *p_type = thermal->trips[trip].type;
0307     return 0;
0308 }
0309 
0310 static int mlxsw_thermal_get_trip_temp(struct thermal_zone_device *tzdev,
0311                        int trip, int *p_temp)
0312 {
0313     struct mlxsw_thermal *thermal = tzdev->devdata;
0314 
0315     if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
0316         return -EINVAL;
0317 
0318     *p_temp = thermal->trips[trip].temp;
0319     return 0;
0320 }
0321 
0322 static int mlxsw_thermal_set_trip_temp(struct thermal_zone_device *tzdev,
0323                        int trip, int temp)
0324 {
0325     struct mlxsw_thermal *thermal = tzdev->devdata;
0326 
0327     if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
0328         return -EINVAL;
0329 
0330     thermal->trips[trip].temp = temp;
0331     return 0;
0332 }
0333 
0334 static int mlxsw_thermal_get_trip_hyst(struct thermal_zone_device *tzdev,
0335                        int trip, int *p_hyst)
0336 {
0337     struct mlxsw_thermal *thermal = tzdev->devdata;
0338 
0339     *p_hyst = thermal->trips[trip].hyst;
0340     return 0;
0341 }
0342 
0343 static int mlxsw_thermal_set_trip_hyst(struct thermal_zone_device *tzdev,
0344                        int trip, int hyst)
0345 {
0346     struct mlxsw_thermal *thermal = tzdev->devdata;
0347 
0348     thermal->trips[trip].hyst = hyst;
0349     return 0;
0350 }
0351 
0352 static int mlxsw_thermal_trend_get(struct thermal_zone_device *tzdev,
0353                    int trip, enum thermal_trend *trend)
0354 {
0355     struct mlxsw_thermal *thermal = tzdev->devdata;
0356 
0357     if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
0358         return -EINVAL;
0359 
0360     if (tzdev == thermal->tz_highest_dev)
0361         return 1;
0362 
0363     *trend = THERMAL_TREND_STABLE;
0364     return 0;
0365 }
0366 
0367 static struct thermal_zone_params mlxsw_thermal_params = {
0368     .no_hwmon = true,
0369 };
0370 
0371 static struct thermal_zone_device_ops mlxsw_thermal_ops = {
0372     .bind = mlxsw_thermal_bind,
0373     .unbind = mlxsw_thermal_unbind,
0374     .get_temp = mlxsw_thermal_get_temp,
0375     .get_trip_type  = mlxsw_thermal_get_trip_type,
0376     .get_trip_temp  = mlxsw_thermal_get_trip_temp,
0377     .set_trip_temp  = mlxsw_thermal_set_trip_temp,
0378     .get_trip_hyst  = mlxsw_thermal_get_trip_hyst,
0379     .set_trip_hyst  = mlxsw_thermal_set_trip_hyst,
0380     .get_trend  = mlxsw_thermal_trend_get,
0381 };
0382 
0383 static int mlxsw_thermal_module_bind(struct thermal_zone_device *tzdev,
0384                      struct thermal_cooling_device *cdev)
0385 {
0386     struct mlxsw_thermal_module *tz = tzdev->devdata;
0387     struct mlxsw_thermal *thermal = tz->parent;
0388     int i, j, err;
0389 
0390     /* If the cooling device is one of ours bind it */
0391     if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0)
0392         return 0;
0393 
0394     for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) {
0395         const struct mlxsw_thermal_trip *trip = &tz->trips[i];
0396 
0397         err = thermal_zone_bind_cooling_device(tzdev, i, cdev,
0398                                trip->max_state,
0399                                trip->min_state,
0400                                THERMAL_WEIGHT_DEFAULT);
0401         if (err < 0)
0402             goto err_thermal_zone_bind_cooling_device;
0403     }
0404     return 0;
0405 
0406 err_thermal_zone_bind_cooling_device:
0407     for (j = i - 1; j >= 0; j--)
0408         thermal_zone_unbind_cooling_device(tzdev, j, cdev);
0409     return err;
0410 }
0411 
0412 static int mlxsw_thermal_module_unbind(struct thermal_zone_device *tzdev,
0413                        struct thermal_cooling_device *cdev)
0414 {
0415     struct mlxsw_thermal_module *tz = tzdev->devdata;
0416     struct mlxsw_thermal *thermal = tz->parent;
0417     int i;
0418     int err;
0419 
0420     /* If the cooling device is one of ours unbind it */
0421     if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0)
0422         return 0;
0423 
0424     for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) {
0425         err = thermal_zone_unbind_cooling_device(tzdev, i, cdev);
0426         WARN_ON(err);
0427     }
0428     return err;
0429 }
0430 
0431 static void
0432 mlxsw_thermal_module_temp_and_thresholds_get(struct mlxsw_core *core,
0433                          u8 slot_index, u16 sensor_index,
0434                          int *p_temp, int *p_crit_temp,
0435                          int *p_emerg_temp)
0436 {
0437     char mtmp_pl[MLXSW_REG_MTMP_LEN];
0438     int err;
0439 
0440     /* Read module temperature and thresholds. */
0441     mlxsw_reg_mtmp_pack(mtmp_pl, slot_index, sensor_index,
0442                 false, false);
0443     err = mlxsw_reg_query(core, MLXSW_REG(mtmp), mtmp_pl);
0444     if (err) {
0445         /* Set temperature and thresholds to zero to avoid passing
0446          * uninitialized data back to the caller.
0447          */
0448         *p_temp = 0;
0449         *p_crit_temp = 0;
0450         *p_emerg_temp = 0;
0451 
0452         return;
0453     }
0454     mlxsw_reg_mtmp_unpack(mtmp_pl, p_temp, NULL, p_crit_temp, p_emerg_temp,
0455                   NULL);
0456 }
0457 
0458 static int mlxsw_thermal_module_temp_get(struct thermal_zone_device *tzdev,
0459                      int *p_temp)
0460 {
0461     struct mlxsw_thermal_module *tz = tzdev->devdata;
0462     struct mlxsw_thermal *thermal = tz->parent;
0463     int temp, crit_temp, emerg_temp;
0464     struct device *dev;
0465     u16 sensor_index;
0466     int err;
0467 
0468     dev = thermal->bus_info->dev;
0469     sensor_index = MLXSW_REG_MTMP_MODULE_INDEX_MIN + tz->module;
0470 
0471     /* Read module temperature and thresholds. */
0472     mlxsw_thermal_module_temp_and_thresholds_get(thermal->core,
0473                              tz->slot_index,
0474                              sensor_index, &temp,
0475                              &crit_temp, &emerg_temp);
0476     *p_temp = temp;
0477 
0478     if (!temp)
0479         return 0;
0480 
0481     /* Update trip points. */
0482     err = mlxsw_thermal_module_trips_update(dev, thermal->core, tz,
0483                         crit_temp, emerg_temp);
0484     if (!err && temp > 0)
0485         mlxsw_thermal_tz_score_update(thermal, tzdev, tz->trips, temp);
0486 
0487     return 0;
0488 }
0489 
0490 static int
0491 mlxsw_thermal_module_trip_type_get(struct thermal_zone_device *tzdev, int trip,
0492                    enum thermal_trip_type *p_type)
0493 {
0494     struct mlxsw_thermal_module *tz = tzdev->devdata;
0495 
0496     if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
0497         return -EINVAL;
0498 
0499     *p_type = tz->trips[trip].type;
0500     return 0;
0501 }
0502 
0503 static int
0504 mlxsw_thermal_module_trip_temp_get(struct thermal_zone_device *tzdev,
0505                    int trip, int *p_temp)
0506 {
0507     struct mlxsw_thermal_module *tz = tzdev->devdata;
0508 
0509     if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
0510         return -EINVAL;
0511 
0512     *p_temp = tz->trips[trip].temp;
0513     return 0;
0514 }
0515 
0516 static int
0517 mlxsw_thermal_module_trip_temp_set(struct thermal_zone_device *tzdev,
0518                    int trip, int temp)
0519 {
0520     struct mlxsw_thermal_module *tz = tzdev->devdata;
0521 
0522     if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
0523         return -EINVAL;
0524 
0525     tz->trips[trip].temp = temp;
0526     return 0;
0527 }
0528 
0529 static int
0530 mlxsw_thermal_module_trip_hyst_get(struct thermal_zone_device *tzdev, int trip,
0531                    int *p_hyst)
0532 {
0533     struct mlxsw_thermal_module *tz = tzdev->devdata;
0534 
0535     *p_hyst = tz->trips[trip].hyst;
0536     return 0;
0537 }
0538 
0539 static int
0540 mlxsw_thermal_module_trip_hyst_set(struct thermal_zone_device *tzdev, int trip,
0541                    int hyst)
0542 {
0543     struct mlxsw_thermal_module *tz = tzdev->devdata;
0544 
0545     tz->trips[trip].hyst = hyst;
0546     return 0;
0547 }
0548 
0549 static int mlxsw_thermal_module_trend_get(struct thermal_zone_device *tzdev,
0550                       int trip, enum thermal_trend *trend)
0551 {
0552     struct mlxsw_thermal_module *tz = tzdev->devdata;
0553     struct mlxsw_thermal *thermal = tz->parent;
0554 
0555     if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
0556         return -EINVAL;
0557 
0558     if (tzdev == thermal->tz_highest_dev)
0559         return 1;
0560 
0561     *trend = THERMAL_TREND_STABLE;
0562     return 0;
0563 }
0564 
0565 static struct thermal_zone_device_ops mlxsw_thermal_module_ops = {
0566     .bind       = mlxsw_thermal_module_bind,
0567     .unbind     = mlxsw_thermal_module_unbind,
0568     .get_temp   = mlxsw_thermal_module_temp_get,
0569     .get_trip_type  = mlxsw_thermal_module_trip_type_get,
0570     .get_trip_temp  = mlxsw_thermal_module_trip_temp_get,
0571     .set_trip_temp  = mlxsw_thermal_module_trip_temp_set,
0572     .get_trip_hyst  = mlxsw_thermal_module_trip_hyst_get,
0573     .set_trip_hyst  = mlxsw_thermal_module_trip_hyst_set,
0574     .get_trend  = mlxsw_thermal_module_trend_get,
0575 };
0576 
0577 static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev,
0578                       int *p_temp)
0579 {
0580     struct mlxsw_thermal_module *tz = tzdev->devdata;
0581     struct mlxsw_thermal *thermal = tz->parent;
0582     char mtmp_pl[MLXSW_REG_MTMP_LEN];
0583     u16 index;
0584     int temp;
0585     int err;
0586 
0587     index = MLXSW_REG_MTMP_GBOX_INDEX_MIN + tz->module;
0588     mlxsw_reg_mtmp_pack(mtmp_pl, tz->slot_index, index, false, false);
0589 
0590     err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl);
0591     if (err)
0592         return err;
0593 
0594     mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL, NULL, NULL);
0595     if (temp > 0)
0596         mlxsw_thermal_tz_score_update(thermal, tzdev, tz->trips, temp);
0597 
0598     *p_temp = temp;
0599     return 0;
0600 }
0601 
0602 static struct thermal_zone_device_ops mlxsw_thermal_gearbox_ops = {
0603     .bind       = mlxsw_thermal_module_bind,
0604     .unbind     = mlxsw_thermal_module_unbind,
0605     .get_temp   = mlxsw_thermal_gearbox_temp_get,
0606     .get_trip_type  = mlxsw_thermal_module_trip_type_get,
0607     .get_trip_temp  = mlxsw_thermal_module_trip_temp_get,
0608     .set_trip_temp  = mlxsw_thermal_module_trip_temp_set,
0609     .get_trip_hyst  = mlxsw_thermal_module_trip_hyst_get,
0610     .set_trip_hyst  = mlxsw_thermal_module_trip_hyst_set,
0611     .get_trend  = mlxsw_thermal_module_trend_get,
0612 };
0613 
0614 static int mlxsw_thermal_get_max_state(struct thermal_cooling_device *cdev,
0615                        unsigned long *p_state)
0616 {
0617     *p_state = MLXSW_THERMAL_MAX_STATE;
0618     return 0;
0619 }
0620 
0621 static int mlxsw_thermal_get_cur_state(struct thermal_cooling_device *cdev,
0622                        unsigned long *p_state)
0623 
0624 {
0625     struct mlxsw_thermal *thermal = cdev->devdata;
0626     struct device *dev = thermal->bus_info->dev;
0627     char mfsc_pl[MLXSW_REG_MFSC_LEN];
0628     int err, idx;
0629     u8 duty;
0630 
0631     idx = mlxsw_get_cooling_device_idx(thermal, cdev);
0632     if (idx < 0)
0633         return idx;
0634 
0635     mlxsw_reg_mfsc_pack(mfsc_pl, idx, 0);
0636     err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfsc), mfsc_pl);
0637     if (err) {
0638         dev_err(dev, "Failed to query PWM duty\n");
0639         return err;
0640     }
0641 
0642     duty = mlxsw_reg_mfsc_pwm_duty_cycle_get(mfsc_pl);
0643     *p_state = mlxsw_duty_to_state(duty);
0644     return 0;
0645 }
0646 
0647 static int mlxsw_thermal_set_cur_state(struct thermal_cooling_device *cdev,
0648                        unsigned long state)
0649 
0650 {
0651     struct mlxsw_thermal *thermal = cdev->devdata;
0652     struct device *dev = thermal->bus_info->dev;
0653     char mfsc_pl[MLXSW_REG_MFSC_LEN];
0654     int idx;
0655     int err;
0656 
0657     if (state > MLXSW_THERMAL_MAX_STATE)
0658         return -EINVAL;
0659 
0660     idx = mlxsw_get_cooling_device_idx(thermal, cdev);
0661     if (idx < 0)
0662         return idx;
0663 
0664     /* Normalize the state to the valid speed range. */
0665     state = thermal->cooling_levels[state];
0666     mlxsw_reg_mfsc_pack(mfsc_pl, idx, mlxsw_state_to_duty(state));
0667     err = mlxsw_reg_write(thermal->core, MLXSW_REG(mfsc), mfsc_pl);
0668     if (err) {
0669         dev_err(dev, "Failed to write PWM duty\n");
0670         return err;
0671     }
0672     return 0;
0673 }
0674 
0675 static const struct thermal_cooling_device_ops mlxsw_cooling_ops = {
0676     .get_max_state  = mlxsw_thermal_get_max_state,
0677     .get_cur_state  = mlxsw_thermal_get_cur_state,
0678     .set_cur_state  = mlxsw_thermal_set_cur_state,
0679 };
0680 
0681 static int
0682 mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz)
0683 {
0684     char tz_name[THERMAL_NAME_LENGTH];
0685     int err;
0686 
0687     if (module_tz->slot_index)
0688         snprintf(tz_name, sizeof(tz_name), "mlxsw-lc%d-module%d",
0689              module_tz->slot_index, module_tz->module + 1);
0690     else
0691         snprintf(tz_name, sizeof(tz_name), "mlxsw-module%d",
0692              module_tz->module + 1);
0693     module_tz->tzdev = thermal_zone_device_register(tz_name,
0694                             MLXSW_THERMAL_NUM_TRIPS,
0695                             MLXSW_THERMAL_TRIP_MASK,
0696                             module_tz,
0697                             &mlxsw_thermal_module_ops,
0698                             &mlxsw_thermal_params,
0699                             0,
0700                             module_tz->parent->polling_delay);
0701     if (IS_ERR(module_tz->tzdev)) {
0702         err = PTR_ERR(module_tz->tzdev);
0703         return err;
0704     }
0705 
0706     err = thermal_zone_device_enable(module_tz->tzdev);
0707     if (err)
0708         thermal_zone_device_unregister(module_tz->tzdev);
0709 
0710     return err;
0711 }
0712 
0713 static void mlxsw_thermal_module_tz_fini(struct thermal_zone_device *tzdev)
0714 {
0715     thermal_zone_device_unregister(tzdev);
0716 }
0717 
0718 static int
0719 mlxsw_thermal_module_init(struct device *dev, struct mlxsw_core *core,
0720               struct mlxsw_thermal *thermal,
0721               struct mlxsw_thermal_area *area, u8 module)
0722 {
0723     struct mlxsw_thermal_module *module_tz;
0724     int dummy_temp, crit_temp, emerg_temp;
0725     u16 sensor_index;
0726 
0727     sensor_index = MLXSW_REG_MTMP_MODULE_INDEX_MIN + module;
0728     module_tz = &area->tz_module_arr[module];
0729     /* Skip if parent is already set (case of port split). */
0730     if (module_tz->parent)
0731         return 0;
0732     module_tz->module = module;
0733     module_tz->slot_index = area->slot_index;
0734     module_tz->parent = thermal;
0735     memcpy(module_tz->trips, default_thermal_trips,
0736            sizeof(thermal->trips));
0737     /* Initialize all trip point. */
0738     mlxsw_thermal_module_trips_reset(module_tz);
0739     /* Read module temperature and thresholds. */
0740     mlxsw_thermal_module_temp_and_thresholds_get(core, area->slot_index,
0741                              sensor_index, &dummy_temp,
0742                              &crit_temp, &emerg_temp);
0743     /* Update trip point according to the module data. */
0744     return mlxsw_thermal_module_trips_update(dev, core, module_tz,
0745                          crit_temp, emerg_temp);
0746 }
0747 
0748 static void mlxsw_thermal_module_fini(struct mlxsw_thermal_module *module_tz)
0749 {
0750     if (module_tz && module_tz->tzdev) {
0751         mlxsw_thermal_module_tz_fini(module_tz->tzdev);
0752         module_tz->tzdev = NULL;
0753         module_tz->parent = NULL;
0754     }
0755 }
0756 
0757 static int
0758 mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core,
0759                struct mlxsw_thermal *thermal,
0760                struct mlxsw_thermal_area *area)
0761 {
0762     struct mlxsw_thermal_module *module_tz;
0763     char mgpir_pl[MLXSW_REG_MGPIR_LEN];
0764     int i, err;
0765 
0766     mlxsw_reg_mgpir_pack(mgpir_pl, area->slot_index);
0767     err = mlxsw_reg_query(core, MLXSW_REG(mgpir), mgpir_pl);
0768     if (err)
0769         return err;
0770 
0771     mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL,
0772                    &area->tz_module_num, NULL);
0773 
0774     /* For modular system module counter could be zero. */
0775     if (!area->tz_module_num)
0776         return 0;
0777 
0778     area->tz_module_arr = kcalloc(area->tz_module_num,
0779                       sizeof(*area->tz_module_arr),
0780                       GFP_KERNEL);
0781     if (!area->tz_module_arr)
0782         return -ENOMEM;
0783 
0784     for (i = 0; i < area->tz_module_num; i++) {
0785         err = mlxsw_thermal_module_init(dev, core, thermal, area, i);
0786         if (err)
0787             goto err_thermal_module_init;
0788     }
0789 
0790     for (i = 0; i < area->tz_module_num; i++) {
0791         module_tz = &area->tz_module_arr[i];
0792         if (!module_tz->parent)
0793             continue;
0794         err = mlxsw_thermal_module_tz_init(module_tz);
0795         if (err)
0796             goto err_thermal_module_tz_init;
0797     }
0798 
0799     return 0;
0800 
0801 err_thermal_module_tz_init:
0802 err_thermal_module_init:
0803     for (i = area->tz_module_num - 1; i >= 0; i--)
0804         mlxsw_thermal_module_fini(&area->tz_module_arr[i]);
0805     kfree(area->tz_module_arr);
0806     return err;
0807 }
0808 
0809 static void
0810 mlxsw_thermal_modules_fini(struct mlxsw_thermal *thermal,
0811                struct mlxsw_thermal_area *area)
0812 {
0813     int i;
0814 
0815     for (i = area->tz_module_num - 1; i >= 0; i--)
0816         mlxsw_thermal_module_fini(&area->tz_module_arr[i]);
0817     kfree(area->tz_module_arr);
0818 }
0819 
0820 static int
0821 mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz)
0822 {
0823     char tz_name[THERMAL_NAME_LENGTH];
0824     int ret;
0825 
0826     if (gearbox_tz->slot_index)
0827         snprintf(tz_name, sizeof(tz_name), "mlxsw-lc%d-gearbox%d",
0828              gearbox_tz->slot_index, gearbox_tz->module + 1);
0829     else
0830         snprintf(tz_name, sizeof(tz_name), "mlxsw-gearbox%d",
0831              gearbox_tz->module + 1);
0832     gearbox_tz->tzdev = thermal_zone_device_register(tz_name,
0833                         MLXSW_THERMAL_NUM_TRIPS,
0834                         MLXSW_THERMAL_TRIP_MASK,
0835                         gearbox_tz,
0836                         &mlxsw_thermal_gearbox_ops,
0837                         &mlxsw_thermal_params, 0,
0838                         gearbox_tz->parent->polling_delay);
0839     if (IS_ERR(gearbox_tz->tzdev))
0840         return PTR_ERR(gearbox_tz->tzdev);
0841 
0842     ret = thermal_zone_device_enable(gearbox_tz->tzdev);
0843     if (ret)
0844         thermal_zone_device_unregister(gearbox_tz->tzdev);
0845 
0846     return ret;
0847 }
0848 
0849 static void
0850 mlxsw_thermal_gearbox_tz_fini(struct mlxsw_thermal_module *gearbox_tz)
0851 {
0852     thermal_zone_device_unregister(gearbox_tz->tzdev);
0853 }
0854 
0855 static int
0856 mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core,
0857                  struct mlxsw_thermal *thermal,
0858                  struct mlxsw_thermal_area *area)
0859 {
0860     enum mlxsw_reg_mgpir_device_type device_type;
0861     struct mlxsw_thermal_module *gearbox_tz;
0862     char mgpir_pl[MLXSW_REG_MGPIR_LEN];
0863     u8 gbox_num;
0864     int i;
0865     int err;
0866 
0867     mlxsw_reg_mgpir_pack(mgpir_pl, area->slot_index);
0868     err = mlxsw_reg_query(core, MLXSW_REG(mgpir), mgpir_pl);
0869     if (err)
0870         return err;
0871 
0872     mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, &device_type, NULL,
0873                    NULL, NULL);
0874     if (device_type != MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE ||
0875         !gbox_num)
0876         return 0;
0877 
0878     area->tz_gearbox_num = gbox_num;
0879     area->tz_gearbox_arr = kcalloc(area->tz_gearbox_num,
0880                        sizeof(*area->tz_gearbox_arr),
0881                        GFP_KERNEL);
0882     if (!area->tz_gearbox_arr)
0883         return -ENOMEM;
0884 
0885     for (i = 0; i < area->tz_gearbox_num; i++) {
0886         gearbox_tz = &area->tz_gearbox_arr[i];
0887         memcpy(gearbox_tz->trips, default_thermal_trips,
0888                sizeof(thermal->trips));
0889         gearbox_tz->module = i;
0890         gearbox_tz->parent = thermal;
0891         gearbox_tz->slot_index = area->slot_index;
0892         err = mlxsw_thermal_gearbox_tz_init(gearbox_tz);
0893         if (err)
0894             goto err_thermal_gearbox_tz_init;
0895     }
0896 
0897     return 0;
0898 
0899 err_thermal_gearbox_tz_init:
0900     for (i--; i >= 0; i--)
0901         mlxsw_thermal_gearbox_tz_fini(&area->tz_gearbox_arr[i]);
0902     kfree(area->tz_gearbox_arr);
0903     return err;
0904 }
0905 
0906 static void
0907 mlxsw_thermal_gearboxes_fini(struct mlxsw_thermal *thermal,
0908                  struct mlxsw_thermal_area *area)
0909 {
0910     int i;
0911 
0912     for (i = area->tz_gearbox_num - 1; i >= 0; i--)
0913         mlxsw_thermal_gearbox_tz_fini(&area->tz_gearbox_arr[i]);
0914     kfree(area->tz_gearbox_arr);
0915 }
0916 
0917 static void
0918 mlxsw_thermal_got_active(struct mlxsw_core *mlxsw_core, u8 slot_index,
0919              void *priv)
0920 {
0921     struct mlxsw_thermal *thermal = priv;
0922     struct mlxsw_thermal_area *linecard;
0923     int err;
0924 
0925     linecard = &thermal->line_cards[slot_index];
0926 
0927     if (linecard->active)
0928         return;
0929 
0930     linecard->slot_index = slot_index;
0931     err = mlxsw_thermal_modules_init(thermal->bus_info->dev, thermal->core,
0932                      thermal, linecard);
0933     if (err) {
0934         dev_err(thermal->bus_info->dev, "Failed to configure thermal objects for line card modules in slot %d\n",
0935             slot_index);
0936         return;
0937     }
0938 
0939     err = mlxsw_thermal_gearboxes_init(thermal->bus_info->dev,
0940                        thermal->core, thermal, linecard);
0941     if (err) {
0942         dev_err(thermal->bus_info->dev, "Failed to configure thermal objects for line card gearboxes in slot %d\n",
0943             slot_index);
0944         goto err_thermal_linecard_gearboxes_init;
0945     }
0946 
0947     linecard->active = true;
0948 
0949     return;
0950 
0951 err_thermal_linecard_gearboxes_init:
0952     mlxsw_thermal_modules_fini(thermal, linecard);
0953 }
0954 
0955 static void
0956 mlxsw_thermal_got_inactive(struct mlxsw_core *mlxsw_core, u8 slot_index,
0957                void *priv)
0958 {
0959     struct mlxsw_thermal *thermal = priv;
0960     struct mlxsw_thermal_area *linecard;
0961 
0962     linecard = &thermal->line_cards[slot_index];
0963     if (!linecard->active)
0964         return;
0965     linecard->active = false;
0966     mlxsw_thermal_gearboxes_fini(thermal, linecard);
0967     mlxsw_thermal_modules_fini(thermal, linecard);
0968 }
0969 
0970 static struct mlxsw_linecards_event_ops mlxsw_thermal_event_ops = {
0971     .got_active = mlxsw_thermal_got_active,
0972     .got_inactive = mlxsw_thermal_got_inactive,
0973 };
0974 
0975 int mlxsw_thermal_init(struct mlxsw_core *core,
0976                const struct mlxsw_bus_info *bus_info,
0977                struct mlxsw_thermal **p_thermal)
0978 {
0979     char mfcr_pl[MLXSW_REG_MFCR_LEN] = { 0 };
0980     enum mlxsw_reg_mfcr_pwm_frequency freq;
0981     struct device *dev = bus_info->dev;
0982     char mgpir_pl[MLXSW_REG_MGPIR_LEN];
0983     struct mlxsw_thermal *thermal;
0984     u8 pwm_active, num_of_slots;
0985     u16 tacho_active;
0986     int err, i;
0987 
0988     mlxsw_reg_mgpir_pack(mgpir_pl, 0);
0989     err = mlxsw_reg_query(core, MLXSW_REG(mgpir), mgpir_pl);
0990     if (err)
0991         return err;
0992 
0993     mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, NULL,
0994                    &num_of_slots);
0995 
0996     thermal = kzalloc(struct_size(thermal, line_cards, num_of_slots + 1),
0997               GFP_KERNEL);
0998     if (!thermal)
0999         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 
1094 err_thermal_zone_device_enable:
1095     mlxsw_linecards_event_ops_unregister(thermal->core,
1096                          &mlxsw_thermal_event_ops,
1097                          thermal);
1098 err_linecards_event_ops_register:
1099     mlxsw_thermal_gearboxes_fini(thermal, &thermal->line_cards[0]);
1100 err_thermal_gearboxes_init:
1101     mlxsw_thermal_modules_fini(thermal, &thermal->line_cards[0]);
1102 err_thermal_modules_init:
1103     if (thermal->tzdev) {
1104         thermal_zone_device_unregister(thermal->tzdev);
1105         thermal->tzdev = NULL;
1106     }
1107 err_thermal_zone_device_register:
1108 err_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]);
1112 err_reg_write:
1113 err_reg_query:
1114     kfree(thermal);
1115     return err;
1116 }
1117 
1118 void 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 }