xref: /linux/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c (revision ab520be8cd5d56867fc95cfbc34b90880faf1f9d)
1 /*
2  * drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
3  * Copyright (c) 2016 Ivan Vecera <cera@cera.cz>
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the names of the copyright holders nor the names of its
14  *    contributors may be used to endorse or promote products derived from
15  *    this software without specific prior written permission.
16  *
17  * Alternatively, this software may be distributed under the terms of the
18  * GNU General Public License ("GPL") version 2 as published by the Free
19  * Software Foundation.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <linux/kernel.h>
35 #include <linux/types.h>
36 #include <linux/device.h>
37 #include <linux/sysfs.h>
38 #include <linux/thermal.h>
39 #include <linux/err.h>
40 
41 #include "core.h"
42 
43 #define MLXSW_THERMAL_POLL_INT	1000	/* ms */
44 #define MLXSW_THERMAL_MAX_TEMP	110000	/* 110C */
45 #define MLXSW_THERMAL_MAX_STATE	10
46 #define MLXSW_THERMAL_MAX_DUTY	255
47 
48 struct mlxsw_thermal_trip {
49 	int	type;
50 	int	temp;
51 	int	min_state;
52 	int	max_state;
53 };
54 
55 static const struct mlxsw_thermal_trip default_thermal_trips[] = {
56 	{	/* In range - 0-40% PWM */
57 		.type		= THERMAL_TRIP_ACTIVE,
58 		.temp		= 75000,
59 		.min_state	= 0,
60 		.max_state	= (4 * MLXSW_THERMAL_MAX_STATE) / 10,
61 	},
62 	{	/* High - 40-100% PWM */
63 		.type		= THERMAL_TRIP_ACTIVE,
64 		.temp		= 80000,
65 		.min_state	= (4 * MLXSW_THERMAL_MAX_STATE) / 10,
66 		.max_state	= MLXSW_THERMAL_MAX_STATE,
67 	},
68 	{
69 		/* Very high - 100% PWM */
70 		.type		= THERMAL_TRIP_ACTIVE,
71 		.temp		= 85000,
72 		.min_state	= MLXSW_THERMAL_MAX_STATE,
73 		.max_state	= MLXSW_THERMAL_MAX_STATE,
74 	},
75 	{	/* Warning */
76 		.type		= THERMAL_TRIP_HOT,
77 		.temp		= 105000,
78 		.min_state	= MLXSW_THERMAL_MAX_STATE,
79 		.max_state	= MLXSW_THERMAL_MAX_STATE,
80 	},
81 	{	/* Critical - soft poweroff */
82 		.type		= THERMAL_TRIP_CRITICAL,
83 		.temp		= MLXSW_THERMAL_MAX_TEMP,
84 		.min_state	= MLXSW_THERMAL_MAX_STATE,
85 		.max_state	= MLXSW_THERMAL_MAX_STATE,
86 	}
87 };
88 
89 #define MLXSW_THERMAL_NUM_TRIPS	ARRAY_SIZE(default_thermal_trips)
90 
91 /* Make sure all trips are writable */
92 #define MLXSW_THERMAL_TRIP_MASK	(BIT(MLXSW_THERMAL_NUM_TRIPS) - 1)
93 
94 struct mlxsw_thermal {
95 	struct mlxsw_core *core;
96 	const struct mlxsw_bus_info *bus_info;
97 	struct thermal_zone_device *tzdev;
98 	struct thermal_cooling_device *cdevs[MLXSW_MFCR_PWMS_MAX];
99 	struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
100 	enum thermal_device_mode mode;
101 };
102 
103 static inline u8 mlxsw_state_to_duty(int state)
104 {
105 	return DIV_ROUND_CLOSEST(state * MLXSW_THERMAL_MAX_DUTY,
106 				 MLXSW_THERMAL_MAX_STATE);
107 }
108 
109 static inline int mlxsw_duty_to_state(u8 duty)
110 {
111 	return DIV_ROUND_CLOSEST(duty * MLXSW_THERMAL_MAX_STATE,
112 				 MLXSW_THERMAL_MAX_DUTY);
113 }
114 
115 static int mlxsw_get_cooling_device_idx(struct mlxsw_thermal *thermal,
116 					struct thermal_cooling_device *cdev)
117 {
118 	int i;
119 
120 	for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++)
121 		if (thermal->cdevs[i] == cdev)
122 			return i;
123 
124 	return -ENODEV;
125 }
126 
127 static int mlxsw_thermal_bind(struct thermal_zone_device *tzdev,
128 			      struct thermal_cooling_device *cdev)
129 {
130 	struct mlxsw_thermal *thermal = tzdev->devdata;
131 	struct device *dev = thermal->bus_info->dev;
132 	int i, err;
133 
134 	/* If the cooling device is one of ours bind it */
135 	if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0)
136 		return 0;
137 
138 	for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) {
139 		const struct mlxsw_thermal_trip *trip = &thermal->trips[i];
140 
141 		err = thermal_zone_bind_cooling_device(tzdev, i, cdev,
142 						       trip->max_state,
143 						       trip->min_state,
144 						       THERMAL_WEIGHT_DEFAULT);
145 		if (err < 0) {
146 			dev_err(dev, "Failed to bind cooling device to trip %d\n", i);
147 			return err;
148 		}
149 	}
150 	return 0;
151 }
152 
153 static int mlxsw_thermal_unbind(struct thermal_zone_device *tzdev,
154 				struct thermal_cooling_device *cdev)
155 {
156 	struct mlxsw_thermal *thermal = tzdev->devdata;
157 	struct device *dev = thermal->bus_info->dev;
158 	int i;
159 	int err;
160 
161 	/* If the cooling device is our one unbind it */
162 	if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0)
163 		return 0;
164 
165 	for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) {
166 		err = thermal_zone_unbind_cooling_device(tzdev, i, cdev);
167 		if (err < 0) {
168 			dev_err(dev, "Failed to unbind cooling device\n");
169 			return err;
170 		}
171 	}
172 	return 0;
173 }
174 
175 static int mlxsw_thermal_get_mode(struct thermal_zone_device *tzdev,
176 				  enum thermal_device_mode *mode)
177 {
178 	struct mlxsw_thermal *thermal = tzdev->devdata;
179 
180 	*mode = thermal->mode;
181 
182 	return 0;
183 }
184 
185 static int mlxsw_thermal_set_mode(struct thermal_zone_device *tzdev,
186 				  enum thermal_device_mode mode)
187 {
188 	struct mlxsw_thermal *thermal = tzdev->devdata;
189 
190 	mutex_lock(&tzdev->lock);
191 
192 	if (mode == THERMAL_DEVICE_ENABLED)
193 		tzdev->polling_delay = MLXSW_THERMAL_POLL_INT;
194 	else
195 		tzdev->polling_delay = 0;
196 
197 	mutex_unlock(&tzdev->lock);
198 
199 	thermal->mode = mode;
200 	thermal_zone_device_update(tzdev, THERMAL_EVENT_UNSPECIFIED);
201 
202 	return 0;
203 }
204 
205 static int mlxsw_thermal_get_temp(struct thermal_zone_device *tzdev,
206 				  int *p_temp)
207 {
208 	struct mlxsw_thermal *thermal = tzdev->devdata;
209 	struct device *dev = thermal->bus_info->dev;
210 	char mtmp_pl[MLXSW_REG_MTMP_LEN];
211 	unsigned int temp;
212 	int err;
213 
214 	mlxsw_reg_mtmp_pack(mtmp_pl, 0, false, false);
215 
216 	err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl);
217 	if (err) {
218 		dev_err(dev, "Failed to query temp sensor\n");
219 		return err;
220 	}
221 	mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL);
222 
223 	*p_temp = (int) temp;
224 	return 0;
225 }
226 
227 static int mlxsw_thermal_get_trip_type(struct thermal_zone_device *tzdev,
228 				       int trip,
229 				       enum thermal_trip_type *p_type)
230 {
231 	struct mlxsw_thermal *thermal = tzdev->devdata;
232 
233 	if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
234 		return -EINVAL;
235 
236 	*p_type = thermal->trips[trip].type;
237 	return 0;
238 }
239 
240 static int mlxsw_thermal_get_trip_temp(struct thermal_zone_device *tzdev,
241 				       int trip, int *p_temp)
242 {
243 	struct mlxsw_thermal *thermal = tzdev->devdata;
244 
245 	if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
246 		return -EINVAL;
247 
248 	*p_temp = thermal->trips[trip].temp;
249 	return 0;
250 }
251 
252 static int mlxsw_thermal_set_trip_temp(struct thermal_zone_device *tzdev,
253 				       int trip, int temp)
254 {
255 	struct mlxsw_thermal *thermal = tzdev->devdata;
256 
257 	if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS ||
258 	    temp > MLXSW_THERMAL_MAX_TEMP)
259 		return -EINVAL;
260 
261 	thermal->trips[trip].temp = temp;
262 	return 0;
263 }
264 
265 static struct thermal_zone_device_ops mlxsw_thermal_ops = {
266 	.bind = mlxsw_thermal_bind,
267 	.unbind = mlxsw_thermal_unbind,
268 	.get_mode = mlxsw_thermal_get_mode,
269 	.set_mode = mlxsw_thermal_set_mode,
270 	.get_temp = mlxsw_thermal_get_temp,
271 	.get_trip_type	= mlxsw_thermal_get_trip_type,
272 	.get_trip_temp	= mlxsw_thermal_get_trip_temp,
273 	.set_trip_temp	= mlxsw_thermal_set_trip_temp,
274 };
275 
276 static int mlxsw_thermal_get_max_state(struct thermal_cooling_device *cdev,
277 				       unsigned long *p_state)
278 {
279 	*p_state = MLXSW_THERMAL_MAX_STATE;
280 	return 0;
281 }
282 
283 static int mlxsw_thermal_get_cur_state(struct thermal_cooling_device *cdev,
284 				       unsigned long *p_state)
285 
286 {
287 	struct mlxsw_thermal *thermal = cdev->devdata;
288 	struct device *dev = thermal->bus_info->dev;
289 	char mfsc_pl[MLXSW_REG_MFSC_LEN];
290 	int err, idx;
291 	u8 duty;
292 
293 	idx = mlxsw_get_cooling_device_idx(thermal, cdev);
294 	if (idx < 0)
295 		return idx;
296 
297 	mlxsw_reg_mfsc_pack(mfsc_pl, idx, 0);
298 	err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfsc), mfsc_pl);
299 	if (err) {
300 		dev_err(dev, "Failed to query PWM duty\n");
301 		return err;
302 	}
303 
304 	duty = mlxsw_reg_mfsc_pwm_duty_cycle_get(mfsc_pl);
305 	*p_state = mlxsw_duty_to_state(duty);
306 	return 0;
307 }
308 
309 static int mlxsw_thermal_set_cur_state(struct thermal_cooling_device *cdev,
310 				       unsigned long state)
311 
312 {
313 	struct mlxsw_thermal *thermal = cdev->devdata;
314 	struct device *dev = thermal->bus_info->dev;
315 	char mfsc_pl[MLXSW_REG_MFSC_LEN];
316 	int err, idx;
317 
318 	idx = mlxsw_get_cooling_device_idx(thermal, cdev);
319 	if (idx < 0)
320 		return idx;
321 
322 	mlxsw_reg_mfsc_pack(mfsc_pl, idx, mlxsw_state_to_duty(state));
323 	err = mlxsw_reg_write(thermal->core, MLXSW_REG(mfsc), mfsc_pl);
324 	if (err) {
325 		dev_err(dev, "Failed to write PWM duty\n");
326 		return err;
327 	}
328 	return 0;
329 }
330 
331 static const struct thermal_cooling_device_ops mlxsw_cooling_ops = {
332 	.get_max_state	= mlxsw_thermal_get_max_state,
333 	.get_cur_state	= mlxsw_thermal_get_cur_state,
334 	.set_cur_state	= mlxsw_thermal_set_cur_state,
335 };
336 
337 int mlxsw_thermal_init(struct mlxsw_core *core,
338 		       const struct mlxsw_bus_info *bus_info,
339 		       struct mlxsw_thermal **p_thermal)
340 {
341 	char mfcr_pl[MLXSW_REG_MFCR_LEN] = { 0 };
342 	enum mlxsw_reg_mfcr_pwm_frequency freq;
343 	struct device *dev = bus_info->dev;
344 	struct mlxsw_thermal *thermal;
345 	u16 tacho_active;
346 	u8 pwm_active;
347 	int err, i;
348 
349 	thermal = devm_kzalloc(dev, sizeof(*thermal),
350 			       GFP_KERNEL);
351 	if (!thermal)
352 		return -ENOMEM;
353 
354 	thermal->core = core;
355 	thermal->bus_info = bus_info;
356 	memcpy(thermal->trips, default_thermal_trips, sizeof(thermal->trips));
357 
358 	err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfcr), mfcr_pl);
359 	if (err) {
360 		dev_err(dev, "Failed to probe PWMs\n");
361 		goto err_free_thermal;
362 	}
363 	mlxsw_reg_mfcr_unpack(mfcr_pl, &freq, &tacho_active, &pwm_active);
364 
365 	for (i = 0; i < MLXSW_MFCR_TACHOS_MAX; i++) {
366 		if (tacho_active & BIT(i)) {
367 			char mfsl_pl[MLXSW_REG_MFSL_LEN];
368 
369 			mlxsw_reg_mfsl_pack(mfsl_pl, i, 0, 0);
370 
371 			/* We need to query the register to preserve maximum */
372 			err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfsl),
373 					      mfsl_pl);
374 			if (err)
375 				goto err_free_thermal;
376 
377 			/* set the minimal RPMs to 0 */
378 			mlxsw_reg_mfsl_tach_min_set(mfsl_pl, 0);
379 			err = mlxsw_reg_write(thermal->core, MLXSW_REG(mfsl),
380 					      mfsl_pl);
381 			if (err)
382 				goto err_free_thermal;
383 		}
384 	}
385 	for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++) {
386 		if (pwm_active & BIT(i)) {
387 			struct thermal_cooling_device *cdev;
388 
389 			cdev = thermal_cooling_device_register("Fan", thermal,
390 							&mlxsw_cooling_ops);
391 			if (IS_ERR(cdev)) {
392 				err = PTR_ERR(cdev);
393 				dev_err(dev, "Failed to register cooling device\n");
394 				goto err_unreg_cdevs;
395 			}
396 			thermal->cdevs[i] = cdev;
397 		}
398 	}
399 
400 	thermal->tzdev = thermal_zone_device_register("mlxsw",
401 						      MLXSW_THERMAL_NUM_TRIPS,
402 						      MLXSW_THERMAL_TRIP_MASK,
403 						      thermal,
404 						      &mlxsw_thermal_ops,
405 						      NULL, 0,
406 						      MLXSW_THERMAL_POLL_INT);
407 	if (IS_ERR(thermal->tzdev)) {
408 		err = PTR_ERR(thermal->tzdev);
409 		dev_err(dev, "Failed to register thermal zone\n");
410 		goto err_unreg_cdevs;
411 	}
412 
413 	thermal->mode = THERMAL_DEVICE_ENABLED;
414 	*p_thermal = thermal;
415 	return 0;
416 err_unreg_cdevs:
417 	for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++)
418 		if (thermal->cdevs[i])
419 			thermal_cooling_device_unregister(thermal->cdevs[i]);
420 err_free_thermal:
421 	devm_kfree(dev, thermal);
422 	return err;
423 }
424 
425 void mlxsw_thermal_fini(struct mlxsw_thermal *thermal)
426 {
427 	int i;
428 
429 	if (thermal->tzdev) {
430 		thermal_zone_device_unregister(thermal->tzdev);
431 		thermal->tzdev = NULL;
432 	}
433 
434 	for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++) {
435 		if (thermal->cdevs[i]) {
436 			thermal_cooling_device_unregister(thermal->cdevs[i]);
437 			thermal->cdevs[i] = NULL;
438 		}
439 	}
440 
441 	devm_kfree(thermal->bus_info->dev, thermal);
442 }
443