brintos

brintos / linux-shallow public Read only

0
0
Text · 21.4 KiB · e746cd9 Raw
786 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/* Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved3 * 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_MODULE_TEMP_NORM	55000	/* 55C */23#define MLXSW_THERMAL_MODULE_TEMP_HIGH	65000	/* 65C */24#define MLXSW_THERMAL_MODULE_TEMP_HOT	80000	/* 80C */25#define MLXSW_THERMAL_HYSTERESIS_TEMP	5000	/* 5C */26#define MLXSW_THERMAL_MODULE_TEMP_SHIFT	(MLXSW_THERMAL_HYSTERESIS_TEMP * 2)27#define MLXSW_THERMAL_MAX_STATE	1028#define MLXSW_THERMAL_MIN_STATE	229#define MLXSW_THERMAL_MAX_DUTY	25530 31/* External cooling devices, allowed for binding to mlxsw thermal zones. */32static char * const mlxsw_thermal_external_allowed_cdev[] = {33	"mlxreg_fan",34	"emc2305",35};36 37struct mlxsw_cooling_states {38	int	min_state;39	int	max_state;40};41 42static const struct thermal_trip default_thermal_trips[] = {43	{	/* In range - 0-40% PWM */44		.type		= THERMAL_TRIP_ACTIVE,45		.temperature	= MLXSW_THERMAL_ASIC_TEMP_NORM,46		.hysteresis	= MLXSW_THERMAL_HYSTERESIS_TEMP,47		.flags		= THERMAL_TRIP_FLAG_RW_TEMP,48	},49	{50		/* In range - 40-100% PWM */51		.type		= THERMAL_TRIP_ACTIVE,52		.temperature	= MLXSW_THERMAL_ASIC_TEMP_HIGH,53		.hysteresis	= MLXSW_THERMAL_HYSTERESIS_TEMP,54		.flags		= THERMAL_TRIP_FLAG_RW_TEMP,55	},56	{	/* Warning */57		.type		= THERMAL_TRIP_HOT,58		.temperature	= MLXSW_THERMAL_ASIC_TEMP_HOT,59		.flags		= THERMAL_TRIP_FLAG_RW_TEMP,60	},61};62 63static const struct thermal_trip default_thermal_module_trips[] = {64	{	/* In range - 0-40% PWM */65		.type		= THERMAL_TRIP_ACTIVE,66		.temperature	= MLXSW_THERMAL_MODULE_TEMP_NORM,67		.hysteresis	= MLXSW_THERMAL_HYSTERESIS_TEMP,68		.flags		= THERMAL_TRIP_FLAG_RW_TEMP,69	},70	{71		/* In range - 40-100% PWM */72		.type		= THERMAL_TRIP_ACTIVE,73		.temperature	= MLXSW_THERMAL_MODULE_TEMP_HIGH,74		.hysteresis	= MLXSW_THERMAL_HYSTERESIS_TEMP,75		.flags		= THERMAL_TRIP_FLAG_RW_TEMP,76	},77	{	/* Warning */78		.type		= THERMAL_TRIP_HOT,79		.temperature	= MLXSW_THERMAL_MODULE_TEMP_HOT,80		.flags		= THERMAL_TRIP_FLAG_RW_TEMP,81	},82};83 84static const struct mlxsw_cooling_states default_cooling_states[] = {85	{86		.min_state	= 0,87		.max_state	= (4 * MLXSW_THERMAL_MAX_STATE) / 10,88	},89	{90		.min_state	= (4 * MLXSW_THERMAL_MAX_STATE) / 10,91		.max_state	= MLXSW_THERMAL_MAX_STATE,92	},93	{94		.min_state	= MLXSW_THERMAL_MAX_STATE,95		.max_state	= MLXSW_THERMAL_MAX_STATE,96	},97};98 99#define MLXSW_THERMAL_NUM_TRIPS	ARRAY_SIZE(default_thermal_trips)100 101struct mlxsw_thermal;102 103struct mlxsw_thermal_cooling_device {104	struct mlxsw_thermal *thermal;105	struct thermal_cooling_device *cdev;106	unsigned int idx;107};108 109struct mlxsw_thermal_module {110	struct mlxsw_thermal *parent;111	struct thermal_zone_device *tzdev;112	struct thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];113	struct mlxsw_cooling_states cooling_states[MLXSW_THERMAL_NUM_TRIPS];114	int module; /* Module or gearbox number */115	u8 slot_index;116};117 118struct mlxsw_thermal_area {119	struct mlxsw_thermal_module *tz_module_arr;120	u8 tz_module_num;121	struct mlxsw_thermal_module *tz_gearbox_arr;122	u8 tz_gearbox_num;123	u8 slot_index;124	bool active;125};126 127struct mlxsw_thermal {128	struct mlxsw_core *core;129	const struct mlxsw_bus_info *bus_info;130	struct thermal_zone_device *tzdev;131	int polling_delay;132	struct mlxsw_thermal_cooling_device cdevs[MLXSW_MFCR_PWMS_MAX];133	struct thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];134	struct mlxsw_cooling_states cooling_states[MLXSW_THERMAL_NUM_TRIPS];135	struct mlxsw_thermal_area line_cards[];136};137 138static inline u8 mlxsw_state_to_duty(int state)139{140	return DIV_ROUND_CLOSEST(state * MLXSW_THERMAL_MAX_DUTY,141				 MLXSW_THERMAL_MAX_STATE);142}143 144static inline int mlxsw_duty_to_state(u8 duty)145{146	return DIV_ROUND_CLOSEST(duty * MLXSW_THERMAL_MAX_STATE,147				 MLXSW_THERMAL_MAX_DUTY);148}149 150static int mlxsw_get_cooling_device_idx(struct mlxsw_thermal *thermal,151					struct thermal_cooling_device *cdev)152{153	int i;154 155	for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++)156		if (thermal->cdevs[i].cdev == cdev)157			return i;158 159	/* Allow mlxsw thermal zone binding to an external cooling device */160	for (i = 0; i < ARRAY_SIZE(mlxsw_thermal_external_allowed_cdev); i++) {161		if (!strcmp(cdev->type, mlxsw_thermal_external_allowed_cdev[i]))162			return 0;163	}164 165	return -ENODEV;166}167 168static bool mlxsw_thermal_should_bind(struct thermal_zone_device *tzdev,169				      const struct thermal_trip *trip,170				      struct thermal_cooling_device *cdev,171				      struct cooling_spec *c)172{173	struct mlxsw_thermal *thermal = thermal_zone_device_priv(tzdev);174	const struct mlxsw_cooling_states *state = trip->priv;175 176	/* If the cooling device is one of ours bind it */177	if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0)178		return false;179 180	c->upper = state->max_state;181	c->lower = state->min_state;182 183	return true;184}185 186static int mlxsw_thermal_get_temp(struct thermal_zone_device *tzdev,187				  int *p_temp)188{189	struct mlxsw_thermal *thermal = thermal_zone_device_priv(tzdev);190	struct device *dev = thermal->bus_info->dev;191	char mtmp_pl[MLXSW_REG_MTMP_LEN];192	int temp;193	int err;194 195	mlxsw_reg_mtmp_pack(mtmp_pl, 0, 0, false, false);196 197	err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl);198	if (err) {199		dev_err(dev, "Failed to query temp sensor\n");200		return err;201	}202	mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL, NULL, NULL);203 204	*p_temp = temp;205	return 0;206}207 208static struct thermal_zone_params mlxsw_thermal_params = {209	.no_hwmon = true,210};211 212static struct thermal_zone_device_ops mlxsw_thermal_ops = {213	.should_bind = mlxsw_thermal_should_bind,214	.get_temp = mlxsw_thermal_get_temp,215};216 217static bool mlxsw_thermal_module_should_bind(struct thermal_zone_device *tzdev,218					     const struct thermal_trip *trip,219					     struct thermal_cooling_device *cdev,220					     struct cooling_spec *c)221{222	struct mlxsw_thermal_module *tz = thermal_zone_device_priv(tzdev);223	const struct mlxsw_cooling_states *state = trip->priv;224	struct mlxsw_thermal *thermal = tz->parent;225 226	/* If the cooling device is one of ours bind it */227	if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0)228		return false;229 230	c->upper = state->max_state;231	c->lower = state->min_state;232 233	return true;234}235 236static int mlxsw_thermal_module_temp_get(struct thermal_zone_device *tzdev,237					 int *p_temp)238{239	struct mlxsw_thermal_module *tz = thermal_zone_device_priv(tzdev);240	struct mlxsw_thermal *thermal = tz->parent;241	char mtmp_pl[MLXSW_REG_MTMP_LEN];242	u16 sensor_index;243	int err;244 245	sensor_index = MLXSW_REG_MTMP_MODULE_INDEX_MIN + tz->module;246	mlxsw_reg_mtmp_pack(mtmp_pl, tz->slot_index, sensor_index,247			    false, false);248	err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl);249	if (err)250		return err;251	mlxsw_reg_mtmp_unpack(mtmp_pl, p_temp, NULL, NULL, NULL, NULL);252	return 0;253}254 255static struct thermal_zone_device_ops mlxsw_thermal_module_ops = {256	.should_bind	= mlxsw_thermal_module_should_bind,257	.get_temp	= mlxsw_thermal_module_temp_get,258};259 260static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev,261					  int *p_temp)262{263	struct mlxsw_thermal_module *tz = thermal_zone_device_priv(tzdev);264	struct mlxsw_thermal *thermal = tz->parent;265	char mtmp_pl[MLXSW_REG_MTMP_LEN];266	u16 index;267	int temp;268	int err;269 270	index = MLXSW_REG_MTMP_GBOX_INDEX_MIN + tz->module;271	mlxsw_reg_mtmp_pack(mtmp_pl, tz->slot_index, index, false, false);272 273	err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl);274	if (err)275		return err;276 277	mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL, NULL, NULL);278 279	*p_temp = temp;280	return 0;281}282 283static struct thermal_zone_device_ops mlxsw_thermal_gearbox_ops = {284	.should_bind	= mlxsw_thermal_module_should_bind,285	.get_temp	= mlxsw_thermal_gearbox_temp_get,286};287 288static int mlxsw_thermal_get_max_state(struct thermal_cooling_device *cdev,289				       unsigned long *p_state)290{291	*p_state = MLXSW_THERMAL_MAX_STATE;292	return 0;293}294 295static int mlxsw_thermal_get_cur_state(struct thermal_cooling_device *cdev,296				       unsigned long *p_state)297 298{299	struct mlxsw_thermal_cooling_device *mlxsw_cdev = cdev->devdata;300	struct mlxsw_thermal *thermal = mlxsw_cdev->thermal;301	struct device *dev = thermal->bus_info->dev;302	char mfsc_pl[MLXSW_REG_MFSC_LEN];303	u8 duty;304	int err;305 306	mlxsw_reg_mfsc_pack(mfsc_pl, mlxsw_cdev->idx, 0);307	err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfsc), mfsc_pl);308	if (err) {309		dev_err(dev, "Failed to query PWM duty\n");310		return err;311	}312 313	duty = mlxsw_reg_mfsc_pwm_duty_cycle_get(mfsc_pl);314	*p_state = mlxsw_duty_to_state(duty);315	return 0;316}317 318static int mlxsw_thermal_set_cur_state(struct thermal_cooling_device *cdev,319				       unsigned long state)320 321{322	struct mlxsw_thermal_cooling_device *mlxsw_cdev = cdev->devdata;323	struct mlxsw_thermal *thermal = mlxsw_cdev->thermal;324	struct device *dev = thermal->bus_info->dev;325	char mfsc_pl[MLXSW_REG_MFSC_LEN];326	int err;327 328	if (state > MLXSW_THERMAL_MAX_STATE)329		return -EINVAL;330 331	/* Normalize the state to the valid speed range. */332	state = max_t(unsigned long, MLXSW_THERMAL_MIN_STATE, state);333	mlxsw_reg_mfsc_pack(mfsc_pl, mlxsw_cdev->idx,334			    mlxsw_state_to_duty(state));335	err = mlxsw_reg_write(thermal->core, MLXSW_REG(mfsc), mfsc_pl);336	if (err) {337		dev_err(dev, "Failed to write PWM duty\n");338		return err;339	}340	return 0;341}342 343static const struct thermal_cooling_device_ops mlxsw_cooling_ops = {344	.get_max_state	= mlxsw_thermal_get_max_state,345	.get_cur_state	= mlxsw_thermal_get_cur_state,346	.set_cur_state	= mlxsw_thermal_set_cur_state,347};348 349static int350mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz)351{352	char tz_name[40];353	int err;354 355	if (module_tz->slot_index)356		snprintf(tz_name, sizeof(tz_name), "mlxsw-lc%d-module%d",357			 module_tz->slot_index, module_tz->module + 1);358	else359		snprintf(tz_name, sizeof(tz_name), "mlxsw-module%d",360			 module_tz->module + 1);361	module_tz->tzdev = thermal_zone_device_register_with_trips(tz_name,362							module_tz->trips,363							MLXSW_THERMAL_NUM_TRIPS,364							module_tz,365							&mlxsw_thermal_module_ops,366							&mlxsw_thermal_params,367							0,368							module_tz->parent->polling_delay);369	if (IS_ERR(module_tz->tzdev)) {370		err = PTR_ERR(module_tz->tzdev);371		return err;372	}373 374	err = thermal_zone_device_enable(module_tz->tzdev);375	if (err)376		thermal_zone_device_unregister(module_tz->tzdev);377 378	return err;379}380 381static void mlxsw_thermal_module_tz_fini(struct thermal_zone_device *tzdev)382{383	thermal_zone_device_unregister(tzdev);384}385 386static int387mlxsw_thermal_module_init(struct mlxsw_thermal *thermal,388			  struct mlxsw_thermal_area *area, u8 module)389{390	struct mlxsw_thermal_module *module_tz;391	int i;392 393	module_tz = &area->tz_module_arr[module];394	module_tz->module = module;395	module_tz->slot_index = area->slot_index;396	module_tz->parent = thermal;397	BUILD_BUG_ON(ARRAY_SIZE(default_thermal_module_trips) !=398		     MLXSW_THERMAL_NUM_TRIPS);399	memcpy(module_tz->trips, default_thermal_module_trips,400	       sizeof(thermal->trips));401	memcpy(module_tz->cooling_states, default_cooling_states,402	       sizeof(thermal->cooling_states));403	for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++)404		module_tz->trips[i].priv = &module_tz->cooling_states[i];405 406	return mlxsw_thermal_module_tz_init(module_tz);407}408 409static void mlxsw_thermal_module_fini(struct mlxsw_thermal_module *module_tz)410{411	mlxsw_thermal_module_tz_fini(module_tz->tzdev);412}413 414static int415mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core,416			   struct mlxsw_thermal *thermal,417			   struct mlxsw_thermal_area *area)418{419	char mgpir_pl[MLXSW_REG_MGPIR_LEN];420	int i, err;421 422	mlxsw_reg_mgpir_pack(mgpir_pl, area->slot_index);423	err = mlxsw_reg_query(core, MLXSW_REG(mgpir), mgpir_pl);424	if (err)425		return err;426 427	mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL,428			       &area->tz_module_num, NULL);429 430	/* For modular system module counter could be zero. */431	if (!area->tz_module_num)432		return 0;433 434	area->tz_module_arr = kcalloc(area->tz_module_num,435				      sizeof(*area->tz_module_arr),436				      GFP_KERNEL);437	if (!area->tz_module_arr)438		return -ENOMEM;439 440	for (i = 0; i < area->tz_module_num; i++) {441		err = mlxsw_thermal_module_init(thermal, area, i);442		if (err)443			goto err_thermal_module_init;444	}445 446	return 0;447 448err_thermal_module_init:449	for (i--; i >= 0; i--)450		mlxsw_thermal_module_fini(&area->tz_module_arr[i]);451	kfree(area->tz_module_arr);452	return err;453}454 455static void456mlxsw_thermal_modules_fini(struct mlxsw_thermal *thermal,457			   struct mlxsw_thermal_area *area)458{459	int i;460 461	for (i = area->tz_module_num - 1; i >= 0; i--)462		mlxsw_thermal_module_fini(&area->tz_module_arr[i]);463	kfree(area->tz_module_arr);464}465 466static int467mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz)468{469	char tz_name[40];470	int ret;471 472	if (gearbox_tz->slot_index)473		snprintf(tz_name, sizeof(tz_name), "mlxsw-lc%d-gearbox%d",474			 gearbox_tz->slot_index, gearbox_tz->module + 1);475	else476		snprintf(tz_name, sizeof(tz_name), "mlxsw-gearbox%d",477			 gearbox_tz->module + 1);478	gearbox_tz->tzdev = thermal_zone_device_register_with_trips(tz_name,479						gearbox_tz->trips,480						MLXSW_THERMAL_NUM_TRIPS,481						gearbox_tz,482						&mlxsw_thermal_gearbox_ops,483						&mlxsw_thermal_params, 0,484						gearbox_tz->parent->polling_delay);485	if (IS_ERR(gearbox_tz->tzdev))486		return PTR_ERR(gearbox_tz->tzdev);487 488	ret = thermal_zone_device_enable(gearbox_tz->tzdev);489	if (ret)490		thermal_zone_device_unregister(gearbox_tz->tzdev);491 492	return ret;493}494 495static void496mlxsw_thermal_gearbox_tz_fini(struct mlxsw_thermal_module *gearbox_tz)497{498	thermal_zone_device_unregister(gearbox_tz->tzdev);499}500 501static int502mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core,503			     struct mlxsw_thermal *thermal,504			     struct mlxsw_thermal_area *area)505{506	enum mlxsw_reg_mgpir_device_type device_type;507	struct mlxsw_thermal_module *gearbox_tz;508	char mgpir_pl[MLXSW_REG_MGPIR_LEN];509	u8 gbox_num;510	int i, j;511	int err;512 513	mlxsw_reg_mgpir_pack(mgpir_pl, area->slot_index);514	err = mlxsw_reg_query(core, MLXSW_REG(mgpir), mgpir_pl);515	if (err)516		return err;517 518	mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, &device_type, NULL,519			       NULL, NULL);520	if (device_type != MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE ||521	    !gbox_num)522		return 0;523 524	area->tz_gearbox_num = gbox_num;525	area->tz_gearbox_arr = kcalloc(area->tz_gearbox_num,526				       sizeof(*area->tz_gearbox_arr),527				       GFP_KERNEL);528	if (!area->tz_gearbox_arr)529		return -ENOMEM;530 531	for (i = 0; i < area->tz_gearbox_num; i++) {532		gearbox_tz = &area->tz_gearbox_arr[i];533		memcpy(gearbox_tz->trips, default_thermal_trips,534		       sizeof(thermal->trips));535		memcpy(gearbox_tz->cooling_states, default_cooling_states,536		       sizeof(thermal->cooling_states));537		for (j = 0; j < MLXSW_THERMAL_NUM_TRIPS; j++)538			gearbox_tz->trips[j].priv = &gearbox_tz->cooling_states[j];539 540		gearbox_tz->module = i;541		gearbox_tz->parent = thermal;542		gearbox_tz->slot_index = area->slot_index;543		err = mlxsw_thermal_gearbox_tz_init(gearbox_tz);544		if (err)545			goto err_thermal_gearbox_tz_init;546	}547 548	return 0;549 550err_thermal_gearbox_tz_init:551	for (i--; i >= 0; i--)552		mlxsw_thermal_gearbox_tz_fini(&area->tz_gearbox_arr[i]);553	kfree(area->tz_gearbox_arr);554	return err;555}556 557static void558mlxsw_thermal_gearboxes_fini(struct mlxsw_thermal *thermal,559			     struct mlxsw_thermal_area *area)560{561	int i;562 563	for (i = area->tz_gearbox_num - 1; i >= 0; i--)564		mlxsw_thermal_gearbox_tz_fini(&area->tz_gearbox_arr[i]);565	kfree(area->tz_gearbox_arr);566}567 568static void569mlxsw_thermal_got_active(struct mlxsw_core *mlxsw_core, u8 slot_index,570			 void *priv)571{572	struct mlxsw_thermal *thermal = priv;573	struct mlxsw_thermal_area *linecard;574	int err;575 576	linecard = &thermal->line_cards[slot_index];577 578	if (linecard->active)579		return;580 581	linecard->slot_index = slot_index;582	err = mlxsw_thermal_modules_init(thermal->bus_info->dev, thermal->core,583					 thermal, linecard);584	if (err) {585		dev_err(thermal->bus_info->dev, "Failed to configure thermal objects for line card modules in slot %d\n",586			slot_index);587		return;588	}589 590	err = mlxsw_thermal_gearboxes_init(thermal->bus_info->dev,591					   thermal->core, thermal, linecard);592	if (err) {593		dev_err(thermal->bus_info->dev, "Failed to configure thermal objects for line card gearboxes in slot %d\n",594			slot_index);595		goto err_thermal_linecard_gearboxes_init;596	}597 598	linecard->active = true;599 600	return;601 602err_thermal_linecard_gearboxes_init:603	mlxsw_thermal_modules_fini(thermal, linecard);604}605 606static void607mlxsw_thermal_got_inactive(struct mlxsw_core *mlxsw_core, u8 slot_index,608			   void *priv)609{610	struct mlxsw_thermal *thermal = priv;611	struct mlxsw_thermal_area *linecard;612 613	linecard = &thermal->line_cards[slot_index];614	if (!linecard->active)615		return;616	linecard->active = false;617	mlxsw_thermal_gearboxes_fini(thermal, linecard);618	mlxsw_thermal_modules_fini(thermal, linecard);619}620 621static struct mlxsw_linecards_event_ops mlxsw_thermal_event_ops = {622	.got_active = mlxsw_thermal_got_active,623	.got_inactive = mlxsw_thermal_got_inactive,624};625 626int mlxsw_thermal_init(struct mlxsw_core *core,627		       const struct mlxsw_bus_info *bus_info,628		       struct mlxsw_thermal **p_thermal)629{630	char mfcr_pl[MLXSW_REG_MFCR_LEN] = { 0 };631	enum mlxsw_reg_mfcr_pwm_frequency freq;632	struct device *dev = bus_info->dev;633	char mgpir_pl[MLXSW_REG_MGPIR_LEN];634	struct mlxsw_thermal *thermal;635	u8 pwm_active, num_of_slots;636	u16 tacho_active;637	int err, i;638 639	mlxsw_reg_mgpir_pack(mgpir_pl, 0);640	err = mlxsw_reg_query(core, MLXSW_REG(mgpir), mgpir_pl);641	if (err)642		return err;643 644	mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, NULL,645			       &num_of_slots);646 647	thermal = kzalloc(struct_size(thermal, line_cards, num_of_slots + 1),648			  GFP_KERNEL);649	if (!thermal)650		return -ENOMEM;651 652	thermal->core = core;653	thermal->bus_info = bus_info;654	memcpy(thermal->trips, default_thermal_trips, sizeof(thermal->trips));655	memcpy(thermal->cooling_states, default_cooling_states, sizeof(thermal->cooling_states));656	for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++)657		thermal->trips[i].priv = &thermal->cooling_states[i];658 659	thermal->line_cards[0].slot_index = 0;660 661	err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfcr), mfcr_pl);662	if (err) {663		dev_err(dev, "Failed to probe PWMs\n");664		goto err_reg_query;665	}666	mlxsw_reg_mfcr_unpack(mfcr_pl, &freq, &tacho_active, &pwm_active);667 668	for (i = 0; i < MLXSW_MFCR_TACHOS_MAX; i++) {669		if (tacho_active & BIT(i)) {670			char mfsl_pl[MLXSW_REG_MFSL_LEN];671 672			mlxsw_reg_mfsl_pack(mfsl_pl, i, 0, 0);673 674			/* We need to query the register to preserve maximum */675			err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfsl),676					      mfsl_pl);677			if (err)678				goto err_reg_query;679 680			/* set the minimal RPMs to 0 */681			mlxsw_reg_mfsl_tach_min_set(mfsl_pl, 0);682			err = mlxsw_reg_write(thermal->core, MLXSW_REG(mfsl),683					      mfsl_pl);684			if (err)685				goto err_reg_write;686		}687	}688	for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++) {689		if (pwm_active & BIT(i)) {690			struct mlxsw_thermal_cooling_device *mlxsw_cdev;691			struct thermal_cooling_device *cdev;692 693			mlxsw_cdev = &thermal->cdevs[i];694			mlxsw_cdev->thermal = thermal;695			mlxsw_cdev->idx = i;696			cdev = thermal_cooling_device_register("mlxsw_fan",697							       mlxsw_cdev,698							       &mlxsw_cooling_ops);699			if (IS_ERR(cdev)) {700				err = PTR_ERR(cdev);701				dev_err(dev, "Failed to register cooling device\n");702				goto err_thermal_cooling_device_register;703			}704			mlxsw_cdev->cdev = cdev;705		}706	}707 708	thermal->polling_delay = bus_info->low_frequency ?709				 MLXSW_THERMAL_SLOW_POLL_INT :710				 MLXSW_THERMAL_POLL_INT;711 712	thermal->tzdev = thermal_zone_device_register_with_trips("mlxsw",713						      thermal->trips,714						      MLXSW_THERMAL_NUM_TRIPS,715						      thermal,716						      &mlxsw_thermal_ops,717						      &mlxsw_thermal_params, 0,718						      thermal->polling_delay);719	if (IS_ERR(thermal->tzdev)) {720		err = PTR_ERR(thermal->tzdev);721		dev_err(dev, "Failed to register thermal zone\n");722		goto err_thermal_zone_device_register;723	}724 725	err = mlxsw_thermal_modules_init(dev, core, thermal,726					 &thermal->line_cards[0]);727	if (err)728		goto err_thermal_modules_init;729 730	err = mlxsw_thermal_gearboxes_init(dev, core, thermal,731					   &thermal->line_cards[0]);732	if (err)733		goto err_thermal_gearboxes_init;734 735	err = mlxsw_linecards_event_ops_register(core,736						 &mlxsw_thermal_event_ops,737						 thermal);738	if (err)739		goto err_linecards_event_ops_register;740 741	err = thermal_zone_device_enable(thermal->tzdev);742	if (err)743		goto err_thermal_zone_device_enable;744 745	thermal->line_cards[0].active = true;746	*p_thermal = thermal;747	return 0;748 749err_thermal_zone_device_enable:750	mlxsw_linecards_event_ops_unregister(thermal->core,751					     &mlxsw_thermal_event_ops,752					     thermal);753err_linecards_event_ops_register:754	mlxsw_thermal_gearboxes_fini(thermal, &thermal->line_cards[0]);755err_thermal_gearboxes_init:756	mlxsw_thermal_modules_fini(thermal, &thermal->line_cards[0]);757err_thermal_modules_init:758	thermal_zone_device_unregister(thermal->tzdev);759err_thermal_zone_device_register:760err_thermal_cooling_device_register:761	for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++)762		thermal_cooling_device_unregister(thermal->cdevs[i].cdev);763err_reg_write:764err_reg_query:765	kfree(thermal);766	return err;767}768 769void mlxsw_thermal_fini(struct mlxsw_thermal *thermal)770{771	int i;772 773	thermal->line_cards[0].active = false;774	mlxsw_linecards_event_ops_unregister(thermal->core,775					     &mlxsw_thermal_event_ops,776					     thermal);777	mlxsw_thermal_gearboxes_fini(thermal, &thermal->line_cards[0]);778	mlxsw_thermal_modules_fini(thermal, &thermal->line_cards[0]);779	thermal_zone_device_unregister(thermal->tzdev);780 781	for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++)782		thermal_cooling_device_unregister(thermal->cdevs[i].cdev);783 784	kfree(thermal);785}786