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
13 #include "core.h"
14
15 #define MLXSW_THERMAL_POLL_INT 1000 /* ms */
16 #define MLXSW_THERMAL_MAX_TEMP 110000 /* 110C */
17 #define MLXSW_THERMAL_MAX_STATE 10
18 #define MLXSW_THERMAL_MAX_DUTY 255
19
20 struct mlxsw_thermal_trip {
21 int type;
22 int temp;
23 int min_state;
24 int max_state;
25 };
26
27 static const struct mlxsw_thermal_trip default_thermal_trips[] = {
28 { /* In range - 0-40% PWM */
29 .type = THERMAL_TRIP_ACTIVE,
30 .temp = 75000,
31 .min_state = 0,
32 .max_state = (4 * MLXSW_THERMAL_MAX_STATE) / 10,
33 },
34 { /* High - 40-100% PWM */
35 .type = THERMAL_TRIP_ACTIVE,
36 .temp = 80000,
37 .min_state = (4 * MLXSW_THERMAL_MAX_STATE) / 10,
38 .max_state = MLXSW_THERMAL_MAX_STATE,
39 },
40 {
41 /* Very high - 100% PWM */
42 .type = THERMAL_TRIP_ACTIVE,
43 .temp = 85000,
44 .min_state = MLXSW_THERMAL_MAX_STATE,
45 .max_state = MLXSW_THERMAL_MAX_STATE,
46 },
47 { /* Warning */
48 .type = THERMAL_TRIP_HOT,
49 .temp = 105000,
50 .min_state = MLXSW_THERMAL_MAX_STATE,
51 .max_state = MLXSW_THERMAL_MAX_STATE,
52 },
53 { /* Critical - soft poweroff */
54 .type = THERMAL_TRIP_CRITICAL,
55 .temp = MLXSW_THERMAL_MAX_TEMP,
56 .min_state = MLXSW_THERMAL_MAX_STATE,
57 .max_state = MLXSW_THERMAL_MAX_STATE,
58 }
59 };
60
61 #define MLXSW_THERMAL_NUM_TRIPS ARRAY_SIZE(default_thermal_trips)
62
63 /* Make sure all trips are writable */
64 #define MLXSW_THERMAL_TRIP_MASK (BIT(MLXSW_THERMAL_NUM_TRIPS) - 1)
65
66 struct mlxsw_thermal {
67 struct mlxsw_core *core;
68 const struct mlxsw_bus_info *bus_info;
69 struct thermal_zone_device *tzdev;
70 struct thermal_cooling_device *cdevs[MLXSW_MFCR_PWMS_MAX];
71 struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
72 enum thermal_device_mode mode;
73 };
74
mlxsw_state_to_duty(int state)75 static inline u8 mlxsw_state_to_duty(int state)
76 {
77 return DIV_ROUND_CLOSEST(state * MLXSW_THERMAL_MAX_DUTY,
78 MLXSW_THERMAL_MAX_STATE);
79 }
80
mlxsw_duty_to_state(u8 duty)81 static inline int mlxsw_duty_to_state(u8 duty)
82 {
83 return DIV_ROUND_CLOSEST(duty * MLXSW_THERMAL_MAX_STATE,
84 MLXSW_THERMAL_MAX_DUTY);
85 }
86
mlxsw_get_cooling_device_idx(struct mlxsw_thermal * thermal,struct thermal_cooling_device * cdev)87 static int mlxsw_get_cooling_device_idx(struct mlxsw_thermal *thermal,
88 struct thermal_cooling_device *cdev)
89 {
90 int i;
91
92 for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++)
93 if (thermal->cdevs[i] == cdev)
94 return i;
95
96 return -ENODEV;
97 }
98
mlxsw_thermal_bind(struct thermal_zone_device * tzdev,struct thermal_cooling_device * cdev)99 static int mlxsw_thermal_bind(struct thermal_zone_device *tzdev,
100 struct thermal_cooling_device *cdev)
101 {
102 struct mlxsw_thermal *thermal = tzdev->devdata;
103 struct device *dev = thermal->bus_info->dev;
104 int i, err;
105
106 /* If the cooling device is one of ours bind it */
107 if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0)
108 return 0;
109
110 for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) {
111 const struct mlxsw_thermal_trip *trip = &thermal->trips[i];
112
113 err = thermal_zone_bind_cooling_device(tzdev, i, cdev,
114 trip->max_state,
115 trip->min_state,
116 THERMAL_WEIGHT_DEFAULT);
117 if (err < 0) {
118 dev_err(dev, "Failed to bind cooling device to trip %d\n", i);
119 return err;
120 }
121 }
122 return 0;
123 }
124
mlxsw_thermal_unbind(struct thermal_zone_device * tzdev,struct thermal_cooling_device * cdev)125 static int mlxsw_thermal_unbind(struct thermal_zone_device *tzdev,
126 struct thermal_cooling_device *cdev)
127 {
128 struct mlxsw_thermal *thermal = tzdev->devdata;
129 struct device *dev = thermal->bus_info->dev;
130 int i;
131 int err;
132
133 /* If the cooling device is our one unbind it */
134 if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0)
135 return 0;
136
137 for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) {
138 err = thermal_zone_unbind_cooling_device(tzdev, i, cdev);
139 if (err < 0) {
140 dev_err(dev, "Failed to unbind cooling device\n");
141 return err;
142 }
143 }
144 return 0;
145 }
146
mlxsw_thermal_get_mode(struct thermal_zone_device * tzdev,enum thermal_device_mode * mode)147 static int mlxsw_thermal_get_mode(struct thermal_zone_device *tzdev,
148 enum thermal_device_mode *mode)
149 {
150 struct mlxsw_thermal *thermal = tzdev->devdata;
151
152 *mode = thermal->mode;
153
154 return 0;
155 }
156
mlxsw_thermal_set_mode(struct thermal_zone_device * tzdev,enum thermal_device_mode mode)157 static int mlxsw_thermal_set_mode(struct thermal_zone_device *tzdev,
158 enum thermal_device_mode mode)
159 {
160 struct mlxsw_thermal *thermal = tzdev->devdata;
161
162 mutex_lock(&tzdev->lock);
163
164 if (mode == THERMAL_DEVICE_ENABLED)
165 tzdev->polling_delay = MLXSW_THERMAL_POLL_INT;
166 else
167 tzdev->polling_delay = 0;
168
169 mutex_unlock(&tzdev->lock);
170
171 thermal->mode = mode;
172 thermal_zone_device_update(tzdev, THERMAL_EVENT_UNSPECIFIED);
173
174 return 0;
175 }
176
mlxsw_thermal_get_temp(struct thermal_zone_device * tzdev,int * p_temp)177 static int mlxsw_thermal_get_temp(struct thermal_zone_device *tzdev,
178 int *p_temp)
179 {
180 struct mlxsw_thermal *thermal = tzdev->devdata;
181 struct device *dev = thermal->bus_info->dev;
182 char mtmp_pl[MLXSW_REG_MTMP_LEN];
183 unsigned int temp;
184 int err;
185
186 mlxsw_reg_mtmp_pack(mtmp_pl, 0, false, false);
187
188 err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl);
189 if (err) {
190 dev_err(dev, "Failed to query temp sensor\n");
191 return err;
192 }
193 mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL);
194
195 *p_temp = (int) temp;
196 return 0;
197 }
198
mlxsw_thermal_get_trip_type(struct thermal_zone_device * tzdev,int trip,enum thermal_trip_type * p_type)199 static int mlxsw_thermal_get_trip_type(struct thermal_zone_device *tzdev,
200 int trip,
201 enum thermal_trip_type *p_type)
202 {
203 struct mlxsw_thermal *thermal = tzdev->devdata;
204
205 if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
206 return -EINVAL;
207
208 *p_type = thermal->trips[trip].type;
209 return 0;
210 }
211
mlxsw_thermal_get_trip_temp(struct thermal_zone_device * tzdev,int trip,int * p_temp)212 static int mlxsw_thermal_get_trip_temp(struct thermal_zone_device *tzdev,
213 int trip, int *p_temp)
214 {
215 struct mlxsw_thermal *thermal = tzdev->devdata;
216
217 if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
218 return -EINVAL;
219
220 *p_temp = thermal->trips[trip].temp;
221 return 0;
222 }
223
mlxsw_thermal_set_trip_temp(struct thermal_zone_device * tzdev,int trip,int temp)224 static int mlxsw_thermal_set_trip_temp(struct thermal_zone_device *tzdev,
225 int trip, int temp)
226 {
227 struct mlxsw_thermal *thermal = tzdev->devdata;
228
229 if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS ||
230 temp > MLXSW_THERMAL_MAX_TEMP)
231 return -EINVAL;
232
233 thermal->trips[trip].temp = temp;
234 return 0;
235 }
236
237 static struct thermal_zone_device_ops mlxsw_thermal_ops = {
238 .bind = mlxsw_thermal_bind,
239 .unbind = mlxsw_thermal_unbind,
240 .get_mode = mlxsw_thermal_get_mode,
241 .set_mode = mlxsw_thermal_set_mode,
242 .get_temp = mlxsw_thermal_get_temp,
243 .get_trip_type = mlxsw_thermal_get_trip_type,
244 .get_trip_temp = mlxsw_thermal_get_trip_temp,
245 .set_trip_temp = mlxsw_thermal_set_trip_temp,
246 };
247
mlxsw_thermal_get_max_state(struct thermal_cooling_device * cdev,unsigned long * p_state)248 static int mlxsw_thermal_get_max_state(struct thermal_cooling_device *cdev,
249 unsigned long *p_state)
250 {
251 *p_state = MLXSW_THERMAL_MAX_STATE;
252 return 0;
253 }
254
mlxsw_thermal_get_cur_state(struct thermal_cooling_device * cdev,unsigned long * p_state)255 static int mlxsw_thermal_get_cur_state(struct thermal_cooling_device *cdev,
256 unsigned long *p_state)
257
258 {
259 struct mlxsw_thermal *thermal = cdev->devdata;
260 struct device *dev = thermal->bus_info->dev;
261 char mfsc_pl[MLXSW_REG_MFSC_LEN];
262 int err, idx;
263 u8 duty;
264
265 idx = mlxsw_get_cooling_device_idx(thermal, cdev);
266 if (idx < 0)
267 return idx;
268
269 mlxsw_reg_mfsc_pack(mfsc_pl, idx, 0);
270 err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfsc), mfsc_pl);
271 if (err) {
272 dev_err(dev, "Failed to query PWM duty\n");
273 return err;
274 }
275
276 duty = mlxsw_reg_mfsc_pwm_duty_cycle_get(mfsc_pl);
277 *p_state = mlxsw_duty_to_state(duty);
278 return 0;
279 }
280
mlxsw_thermal_set_cur_state(struct thermal_cooling_device * cdev,unsigned long state)281 static int mlxsw_thermal_set_cur_state(struct thermal_cooling_device *cdev,
282 unsigned long state)
283
284 {
285 struct mlxsw_thermal *thermal = cdev->devdata;
286 struct device *dev = thermal->bus_info->dev;
287 char mfsc_pl[MLXSW_REG_MFSC_LEN];
288 int err, idx;
289
290 idx = mlxsw_get_cooling_device_idx(thermal, cdev);
291 if (idx < 0)
292 return idx;
293
294 mlxsw_reg_mfsc_pack(mfsc_pl, idx, mlxsw_state_to_duty(state));
295 err = mlxsw_reg_write(thermal->core, MLXSW_REG(mfsc), mfsc_pl);
296 if (err) {
297 dev_err(dev, "Failed to write PWM duty\n");
298 return err;
299 }
300 return 0;
301 }
302
303 static const struct thermal_cooling_device_ops mlxsw_cooling_ops = {
304 .get_max_state = mlxsw_thermal_get_max_state,
305 .get_cur_state = mlxsw_thermal_get_cur_state,
306 .set_cur_state = mlxsw_thermal_set_cur_state,
307 };
308
mlxsw_thermal_init(struct mlxsw_core * core,const struct mlxsw_bus_info * bus_info,struct mlxsw_thermal ** p_thermal)309 int mlxsw_thermal_init(struct mlxsw_core *core,
310 const struct mlxsw_bus_info *bus_info,
311 struct mlxsw_thermal **p_thermal)
312 {
313 char mfcr_pl[MLXSW_REG_MFCR_LEN] = { 0 };
314 enum mlxsw_reg_mfcr_pwm_frequency freq;
315 struct device *dev = bus_info->dev;
316 struct mlxsw_thermal *thermal;
317 u16 tacho_active;
318 u8 pwm_active;
319 int err, i;
320
321 thermal = devm_kzalloc(dev, sizeof(*thermal),
322 GFP_KERNEL);
323 if (!thermal)
324 return -ENOMEM;
325
326 thermal->core = core;
327 thermal->bus_info = bus_info;
328 memcpy(thermal->trips, default_thermal_trips, sizeof(thermal->trips));
329
330 err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfcr), mfcr_pl);
331 if (err) {
332 dev_err(dev, "Failed to probe PWMs\n");
333 goto err_free_thermal;
334 }
335 mlxsw_reg_mfcr_unpack(mfcr_pl, &freq, &tacho_active, &pwm_active);
336
337 for (i = 0; i < MLXSW_MFCR_TACHOS_MAX; i++) {
338 if (tacho_active & BIT(i)) {
339 char mfsl_pl[MLXSW_REG_MFSL_LEN];
340
341 mlxsw_reg_mfsl_pack(mfsl_pl, i, 0, 0);
342
343 /* We need to query the register to preserve maximum */
344 err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfsl),
345 mfsl_pl);
346 if (err)
347 goto err_free_thermal;
348
349 /* set the minimal RPMs to 0 */
350 mlxsw_reg_mfsl_tach_min_set(mfsl_pl, 0);
351 err = mlxsw_reg_write(thermal->core, MLXSW_REG(mfsl),
352 mfsl_pl);
353 if (err)
354 goto err_free_thermal;
355 }
356 }
357 for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++) {
358 if (pwm_active & BIT(i)) {
359 struct thermal_cooling_device *cdev;
360
361 cdev = thermal_cooling_device_register("Fan", thermal,
362 &mlxsw_cooling_ops);
363 if (IS_ERR(cdev)) {
364 err = PTR_ERR(cdev);
365 dev_err(dev, "Failed to register cooling device\n");
366 goto err_unreg_cdevs;
367 }
368 thermal->cdevs[i] = cdev;
369 }
370 }
371
372 thermal->tzdev = thermal_zone_device_register("mlxsw",
373 MLXSW_THERMAL_NUM_TRIPS,
374 MLXSW_THERMAL_TRIP_MASK,
375 thermal,
376 &mlxsw_thermal_ops,
377 NULL, 0,
378 MLXSW_THERMAL_POLL_INT);
379 if (IS_ERR(thermal->tzdev)) {
380 err = PTR_ERR(thermal->tzdev);
381 dev_err(dev, "Failed to register thermal zone\n");
382 goto err_unreg_cdevs;
383 }
384
385 thermal->mode = THERMAL_DEVICE_ENABLED;
386 *p_thermal = thermal;
387 return 0;
388 err_unreg_cdevs:
389 for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++)
390 if (thermal->cdevs[i])
391 thermal_cooling_device_unregister(thermal->cdevs[i]);
392 err_free_thermal:
393 devm_kfree(dev, thermal);
394 return err;
395 }
396
mlxsw_thermal_fini(struct mlxsw_thermal * thermal)397 void mlxsw_thermal_fini(struct mlxsw_thermal *thermal)
398 {
399 int i;
400
401 if (thermal->tzdev) {
402 thermal_zone_device_unregister(thermal->tzdev);
403 thermal->tzdev = NULL;
404 }
405
406 for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++) {
407 if (thermal->cdevs[i]) {
408 thermal_cooling_device_unregister(thermal->cdevs[i]);
409 thermal->cdevs[i] = NULL;
410 }
411 }
412
413 devm_kfree(thermal->bus_info->dev, thermal);
414 }
415