cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

core_thermal.c (31002B)


      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}