GNU Linux-libre 4.14.251-gnu1
[releases.git] / drivers / net / ethernet / mellanox / mlxsw / core_thermal.c
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 }