File Index
Files and directories
Sign in
FILE

core_thermal.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c C
  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_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	10
 28#define MLXSW_THERMAL_MIN_STATE	2
 29#define MLXSW_THERMAL_MAX_DUTY	255
 30
 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 const struct thermal_zone_params mlxsw_thermal_params = {
209	.no_hwmon = true,
210};
211
212static const 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 const 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 const 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 int
350mlxsw_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	else
359		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 int
387mlxsw_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 int
415mlxsw_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 void
456mlxsw_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 int
467mlxsw_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	else
476		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 void
496mlxsw_thermal_gearbox_tz_fini(struct mlxsw_thermal_module *gearbox_tz)
497{
498	thermal_zone_device_unregister(gearbox_tz->tzdev);
499}
500
501static int
502mlxsw_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 void
558mlxsw_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 void
569mlxsw_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 void
607mlxsw_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}
~/ Read-only file preview.