2 * drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
3 * Copyright (c) 2016 Ivan Vecera <cera@cera.cz>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
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.
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.
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.
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>
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
48 struct mlxsw_thermal_trip
{
55 static const struct mlxsw_thermal_trip default_thermal_trips
[] = {
56 { /* In range - 0-40% PWM */
57 .type
= THERMAL_TRIP_ACTIVE
,
60 .max_state
= (4 * MLXSW_THERMAL_MAX_STATE
) / 10,
62 { /* High - 40-100% PWM */
63 .type
= THERMAL_TRIP_ACTIVE
,
65 .min_state
= (4 * MLXSW_THERMAL_MAX_STATE
) / 10,
66 .max_state
= MLXSW_THERMAL_MAX_STATE
,
69 /* Very high - 100% PWM */
70 .type
= THERMAL_TRIP_ACTIVE
,
72 .min_state
= MLXSW_THERMAL_MAX_STATE
,
73 .max_state
= MLXSW_THERMAL_MAX_STATE
,
76 .type
= THERMAL_TRIP_HOT
,
78 .min_state
= MLXSW_THERMAL_MAX_STATE
,
79 .max_state
= MLXSW_THERMAL_MAX_STATE
,
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
,
89 #define MLXSW_THERMAL_NUM_TRIPS ARRAY_SIZE(default_thermal_trips)
91 /* Make sure all trips are writable */
92 #define MLXSW_THERMAL_TRIP_MASK (BIT(MLXSW_THERMAL_NUM_TRIPS) - 1)
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
;
103 static inline u8
mlxsw_state_to_duty(int state
)
105 return DIV_ROUND_CLOSEST(state
* MLXSW_THERMAL_MAX_DUTY
,
106 MLXSW_THERMAL_MAX_STATE
);
109 static inline int mlxsw_duty_to_state(u8 duty
)
111 return DIV_ROUND_CLOSEST(duty
* MLXSW_THERMAL_MAX_STATE
,
112 MLXSW_THERMAL_MAX_DUTY
);
115 static int mlxsw_get_cooling_device_idx(struct mlxsw_thermal
*thermal
,
116 struct thermal_cooling_device
*cdev
)
120 for (i
= 0; i
< MLXSW_MFCR_PWMS_MAX
; i
++)
121 if (thermal
->cdevs
[i
] == cdev
)
127 static int mlxsw_thermal_bind(struct thermal_zone_device
*tzdev
,
128 struct thermal_cooling_device
*cdev
)
130 struct mlxsw_thermal
*thermal
= tzdev
->devdata
;
131 struct device
*dev
= thermal
->bus_info
->dev
;
134 /* If the cooling device is one of ours bind it */
135 if (mlxsw_get_cooling_device_idx(thermal
, cdev
) < 0)
138 for (i
= 0; i
< MLXSW_THERMAL_NUM_TRIPS
; i
++) {
139 const struct mlxsw_thermal_trip
*trip
= &thermal
->trips
[i
];
141 err
= thermal_zone_bind_cooling_device(tzdev
, i
, cdev
,
144 THERMAL_WEIGHT_DEFAULT
);
146 dev_err(dev
, "Failed to bind cooling device to trip %d\n", i
);
153 static int mlxsw_thermal_unbind(struct thermal_zone_device
*tzdev
,
154 struct thermal_cooling_device
*cdev
)
156 struct mlxsw_thermal
*thermal
= tzdev
->devdata
;
157 struct device
*dev
= thermal
->bus_info
->dev
;
161 /* If the cooling device is our one unbind it */
162 if (mlxsw_get_cooling_device_idx(thermal
, cdev
) < 0)
165 for (i
= 0; i
< MLXSW_THERMAL_NUM_TRIPS
; i
++) {
166 err
= thermal_zone_unbind_cooling_device(tzdev
, i
, cdev
);
168 dev_err(dev
, "Failed to unbind cooling device\n");
175 static int mlxsw_thermal_get_mode(struct thermal_zone_device
*tzdev
,
176 enum thermal_device_mode
*mode
)
178 struct mlxsw_thermal
*thermal
= tzdev
->devdata
;
180 *mode
= thermal
->mode
;
185 static int mlxsw_thermal_set_mode(struct thermal_zone_device
*tzdev
,
186 enum thermal_device_mode mode
)
188 struct mlxsw_thermal
*thermal
= tzdev
->devdata
;
190 mutex_lock(&tzdev
->lock
);
192 if (mode
== THERMAL_DEVICE_ENABLED
)
193 tzdev
->polling_delay
= MLXSW_THERMAL_POLL_INT
;
195 tzdev
->polling_delay
= 0;
197 mutex_unlock(&tzdev
->lock
);
199 thermal
->mode
= mode
;
200 thermal_zone_device_update(tzdev
, THERMAL_EVENT_UNSPECIFIED
);
205 static int mlxsw_thermal_get_temp(struct thermal_zone_device
*tzdev
,
208 struct mlxsw_thermal
*thermal
= tzdev
->devdata
;
209 struct device
*dev
= thermal
->bus_info
->dev
;
210 char mtmp_pl
[MLXSW_REG_MTMP_LEN
];
214 mlxsw_reg_mtmp_pack(mtmp_pl
, 0, false, false);
216 err
= mlxsw_reg_query(thermal
->core
, MLXSW_REG(mtmp
), mtmp_pl
);
218 dev_err(dev
, "Failed to query temp sensor\n");
221 mlxsw_reg_mtmp_unpack(mtmp_pl
, &temp
, NULL
, NULL
);
223 *p_temp
= (int) temp
;
227 static int mlxsw_thermal_get_trip_type(struct thermal_zone_device
*tzdev
,
229 enum thermal_trip_type
*p_type
)
231 struct mlxsw_thermal
*thermal
= tzdev
->devdata
;
233 if (trip
< 0 || trip
>= MLXSW_THERMAL_NUM_TRIPS
)
236 *p_type
= thermal
->trips
[trip
].type
;
240 static int mlxsw_thermal_get_trip_temp(struct thermal_zone_device
*tzdev
,
241 int trip
, int *p_temp
)
243 struct mlxsw_thermal
*thermal
= tzdev
->devdata
;
245 if (trip
< 0 || trip
>= MLXSW_THERMAL_NUM_TRIPS
)
248 *p_temp
= thermal
->trips
[trip
].temp
;
252 static int mlxsw_thermal_set_trip_temp(struct thermal_zone_device
*tzdev
,
255 struct mlxsw_thermal
*thermal
= tzdev
->devdata
;
257 if (trip
< 0 || trip
>= MLXSW_THERMAL_NUM_TRIPS
||
258 temp
> MLXSW_THERMAL_MAX_TEMP
)
261 thermal
->trips
[trip
].temp
= temp
;
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
,
276 static int mlxsw_thermal_get_max_state(struct thermal_cooling_device
*cdev
,
277 unsigned long *p_state
)
279 *p_state
= MLXSW_THERMAL_MAX_STATE
;
283 static int mlxsw_thermal_get_cur_state(struct thermal_cooling_device
*cdev
,
284 unsigned long *p_state
)
287 struct mlxsw_thermal
*thermal
= cdev
->devdata
;
288 struct device
*dev
= thermal
->bus_info
->dev
;
289 char mfsc_pl
[MLXSW_REG_MFSC_LEN
];
293 idx
= mlxsw_get_cooling_device_idx(thermal
, cdev
);
297 mlxsw_reg_mfsc_pack(mfsc_pl
, idx
, 0);
298 err
= mlxsw_reg_query(thermal
->core
, MLXSW_REG(mfsc
), mfsc_pl
);
300 dev_err(dev
, "Failed to query PWM duty\n");
304 duty
= mlxsw_reg_mfsc_pwm_duty_cycle_get(mfsc_pl
);
305 *p_state
= mlxsw_duty_to_state(duty
);
309 static int mlxsw_thermal_set_cur_state(struct thermal_cooling_device
*cdev
,
313 struct mlxsw_thermal
*thermal
= cdev
->devdata
;
314 struct device
*dev
= thermal
->bus_info
->dev
;
315 char mfsc_pl
[MLXSW_REG_MFSC_LEN
];
318 idx
= mlxsw_get_cooling_device_idx(thermal
, cdev
);
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
);
325 dev_err(dev
, "Failed to write PWM duty\n");
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
,
337 int mlxsw_thermal_init(struct mlxsw_core
*core
,
338 const struct mlxsw_bus_info
*bus_info
,
339 struct mlxsw_thermal
**p_thermal
)
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
;
349 thermal
= devm_kzalloc(dev
, sizeof(*thermal
),
354 thermal
->core
= core
;
355 thermal
->bus_info
= bus_info
;
356 memcpy(thermal
->trips
, default_thermal_trips
, sizeof(thermal
->trips
));
358 err
= mlxsw_reg_query(thermal
->core
, MLXSW_REG(mfcr
), mfcr_pl
);
360 dev_err(dev
, "Failed to probe PWMs\n");
361 goto err_free_thermal
;
363 mlxsw_reg_mfcr_unpack(mfcr_pl
, &freq
, &tacho_active
, &pwm_active
);
365 for (i
= 0; i
< MLXSW_MFCR_TACHOS_MAX
; i
++) {
366 if (tacho_active
& BIT(i
)) {
367 char mfsl_pl
[MLXSW_REG_MFSL_LEN
];
369 mlxsw_reg_mfsl_pack(mfsl_pl
, i
, 0, 0);
371 /* We need to query the register to preserve maximum */
372 err
= mlxsw_reg_query(thermal
->core
, MLXSW_REG(mfsl
),
375 goto err_free_thermal
;
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
),
382 goto err_free_thermal
;
385 for (i
= 0; i
< MLXSW_MFCR_PWMS_MAX
; i
++) {
386 if (pwm_active
& BIT(i
)) {
387 struct thermal_cooling_device
*cdev
;
389 cdev
= thermal_cooling_device_register("Fan", thermal
,
393 dev_err(dev
, "Failed to register cooling device\n");
394 goto err_unreg_cdevs
;
396 thermal
->cdevs
[i
] = cdev
;
400 thermal
->tzdev
= thermal_zone_device_register("mlxsw",
401 MLXSW_THERMAL_NUM_TRIPS
,
402 MLXSW_THERMAL_TRIP_MASK
,
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
;
413 thermal
->mode
= THERMAL_DEVICE_ENABLED
;
414 *p_thermal
= thermal
;
417 for (i
= 0; i
< MLXSW_MFCR_PWMS_MAX
; i
++)
418 if (thermal
->cdevs
[i
])
419 thermal_cooling_device_unregister(thermal
->cdevs
[i
]);
421 devm_kfree(dev
, thermal
);
425 void mlxsw_thermal_fini(struct mlxsw_thermal
*thermal
)
429 if (thermal
->tzdev
) {
430 thermal_zone_device_unregister(thermal
->tzdev
);
431 thermal
->tzdev
= NULL
;
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
;
441 devm_kfree(thermal
->bus_info
->dev
, thermal
);