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 },
48 {
49 /* In range - 40-100% PWM */
50 .type = THERMAL_TRIP_ACTIVE,
51 .temperature = MLXSW_THERMAL_ASIC_TEMP_HIGH,
52 .hysteresis = MLXSW_THERMAL_HYSTERESIS_TEMP,
53 },
54 { /* Warning */
55 .type = THERMAL_TRIP_HOT,
56 .temperature = MLXSW_THERMAL_ASIC_TEMP_HOT,
57 },
58};
59
60static const struct thermal_trip default_thermal_module_trips[] = {
61 { /* In range - 0-40% PWM */
62 .type = THERMAL_TRIP_ACTIVE,
63 .temperature = MLXSW_THERMAL_MODULE_TEMP_NORM,
64 .hysteresis = MLXSW_THERMAL_HYSTERESIS_TEMP,
65 },
66 {
67 /* In range - 40-100% PWM */
68 .type = THERMAL_TRIP_ACTIVE,
69 .temperature = MLXSW_THERMAL_MODULE_TEMP_HIGH,
70 .hysteresis = MLXSW_THERMAL_HYSTERESIS_TEMP,
71 },
72 { /* Warning */
73 .type = THERMAL_TRIP_HOT,
74 .temperature = MLXSW_THERMAL_MODULE_TEMP_HOT,
75 },
76};
77
78static const struct mlxsw_cooling_states default_cooling_states[] = {
79 {
80 .min_state = 0,
81 .max_state = (4 * MLXSW_THERMAL_MAX_STATE) / 10,
82 },
83 {
84 .min_state = (4 * MLXSW_THERMAL_MAX_STATE) / 10,
85 .max_state = MLXSW_THERMAL_MAX_STATE,
86 },
87 {
88 .min_state = MLXSW_THERMAL_MAX_STATE,
89 .max_state = MLXSW_THERMAL_MAX_STATE,
90 },
91};
92
93#define MLXSW_THERMAL_NUM_TRIPS ARRAY_SIZE(default_thermal_trips)
94
95/* Make sure all trips are writable */
96#define MLXSW_THERMAL_TRIP_MASK (BIT(MLXSW_THERMAL_NUM_TRIPS) - 1)
97
98struct mlxsw_thermal;
99
100struct mlxsw_thermal_module {
101 struct mlxsw_thermal *parent;
102 struct thermal_zone_device *tzdev;
103 struct thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
104 struct mlxsw_cooling_states cooling_states[MLXSW_THERMAL_NUM_TRIPS];
105 int module; /* Module or gearbox number */
106 u8 slot_index;
107};
108
109struct mlxsw_thermal_area {
110 struct mlxsw_thermal_module *tz_module_arr;
111 u8 tz_module_num;
112 struct mlxsw_thermal_module *tz_gearbox_arr;
113 u8 tz_gearbox_num;
114 u8 slot_index;
115 bool active;
116};
117
118struct mlxsw_thermal {
119 struct mlxsw_core *core;
120 const struct mlxsw_bus_info *bus_info;
121 struct thermal_zone_device *tzdev;
122 int polling_delay;
123 struct thermal_cooling_device *cdevs[MLXSW_MFCR_PWMS_MAX];
124 struct thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
125 struct mlxsw_cooling_states cooling_states[MLXSW_THERMAL_NUM_TRIPS];
126 struct mlxsw_thermal_area line_cards[];
127};
128
129static inline u8 mlxsw_state_to_duty(int state)
130{
131 return DIV_ROUND_CLOSEST(state * MLXSW_THERMAL_MAX_DUTY,
132 MLXSW_THERMAL_MAX_STATE);
133}
134
135static inline int mlxsw_duty_to_state(u8 duty)
136{
137 return DIV_ROUND_CLOSEST(duty * MLXSW_THERMAL_MAX_STATE,
138 MLXSW_THERMAL_MAX_DUTY);
139}
140
141static int mlxsw_get_cooling_device_idx(struct mlxsw_thermal *thermal,
142 struct thermal_cooling_device *cdev)
143{
144 int i;
145
146 for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++)
147 if (thermal->cdevs[i] == cdev)
148 return i;
149
150 /* Allow mlxsw thermal zone binding to an external cooling device */
151 for (i = 0; i < ARRAY_SIZE(mlxsw_thermal_external_allowed_cdev); i++) {
152 if (!strcmp(cdev->type, mlxsw_thermal_external_allowed_cdev[i]))
153 return 0;
154 }
155
156 return -ENODEV;
157}
158
159static int mlxsw_thermal_bind(struct thermal_zone_device *tzdev,
160 struct thermal_cooling_device *cdev)
161{
162 struct mlxsw_thermal *thermal = thermal_zone_device_priv(tzd: tzdev);
163 struct device *dev = thermal->bus_info->dev;
164 int i, err;
165
166 /* If the cooling device is one of ours bind it */
167 if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0)
168 return 0;
169
170 for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) {
171 const struct mlxsw_cooling_states *state = &thermal->cooling_states[i];
172
173 err = thermal_zone_bind_cooling_device(tzdev, i, cdev,
174 state->max_state,
175 state->min_state,
176 THERMAL_WEIGHT_DEFAULT);
177 if (err < 0) {
178 dev_err(dev, "Failed to bind cooling device to trip %d\n", i);
179 return err;
180 }
181 }
182 return 0;
183}
184
185static int mlxsw_thermal_unbind(struct thermal_zone_device *tzdev,
186 struct thermal_cooling_device *cdev)
187{
188 struct mlxsw_thermal *thermal = thermal_zone_device_priv(tzd: tzdev);
189 struct device *dev = thermal->bus_info->dev;
190 int i;
191 int err;
192
193 /* If the cooling device is our one unbind it */
194 if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0)
195 return 0;
196
197 for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) {
198 err = thermal_zone_unbind_cooling_device(tzdev, i, cdev);
199 if (err < 0) {
200 dev_err(dev, "Failed to unbind cooling device\n");
201 return err;
202 }
203 }
204 return 0;
205}
206
207static int mlxsw_thermal_get_temp(struct thermal_zone_device *tzdev,
208 int *p_temp)
209{
210 struct mlxsw_thermal *thermal = thermal_zone_device_priv(tzd: tzdev);
211 struct device *dev = thermal->bus_info->dev;
212 char mtmp_pl[MLXSW_REG_MTMP_LEN];
213 int temp;
214 int err;
215
216 mlxsw_reg_mtmp_pack(payload: mtmp_pl, slot_index: 0, sensor_index: 0, max_temp_enable: false, max_temp_reset: false);
217
218 err = mlxsw_reg_query(mlxsw_core: thermal->core, MLXSW_REG(mtmp), payload: mtmp_pl);
219 if (err) {
220 dev_err(dev, "Failed to query temp sensor\n");
221 return err;
222 }
223 mlxsw_reg_mtmp_unpack(payload: mtmp_pl, p_temp: &temp, NULL, NULL, NULL, NULL);
224
225 *p_temp = temp;
226 return 0;
227}
228
229static struct thermal_zone_params mlxsw_thermal_params = {
230 .no_hwmon = true,
231};
232
233static struct thermal_zone_device_ops mlxsw_thermal_ops = {
234 .bind = mlxsw_thermal_bind,
235 .unbind = mlxsw_thermal_unbind,
236 .get_temp = mlxsw_thermal_get_temp,
237};
238
239static int mlxsw_thermal_module_bind(struct thermal_zone_device *tzdev,
240 struct thermal_cooling_device *cdev)
241{
242 struct mlxsw_thermal_module *tz = thermal_zone_device_priv(tzd: tzdev);
243 struct mlxsw_thermal *thermal = tz->parent;
244 int i, j, err;
245
246 /* If the cooling device is one of ours bind it */
247 if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0)
248 return 0;
249
250 for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) {
251 const struct mlxsw_cooling_states *state = &tz->cooling_states[i];
252
253 err = thermal_zone_bind_cooling_device(tzdev, i, cdev,
254 state->max_state,
255 state->min_state,
256 THERMAL_WEIGHT_DEFAULT);
257 if (err < 0)
258 goto err_thermal_zone_bind_cooling_device;
259 }
260 return 0;
261
262err_thermal_zone_bind_cooling_device:
263 for (j = i - 1; j >= 0; j--)
264 thermal_zone_unbind_cooling_device(tzdev, j, cdev);
265 return err;
266}
267
268static int mlxsw_thermal_module_unbind(struct thermal_zone_device *tzdev,
269 struct thermal_cooling_device *cdev)
270{
271 struct mlxsw_thermal_module *tz = thermal_zone_device_priv(tzd: tzdev);
272 struct mlxsw_thermal *thermal = tz->parent;
273 int i;
274 int err;
275
276 /* If the cooling device is one of ours unbind it */
277 if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0)
278 return 0;
279
280 for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) {
281 err = thermal_zone_unbind_cooling_device(tzdev, i, cdev);
282 WARN_ON(err);
283 }
284 return err;
285}
286
287static int mlxsw_thermal_module_temp_get(struct thermal_zone_device *tzdev,
288 int *p_temp)
289{
290 struct mlxsw_thermal_module *tz = thermal_zone_device_priv(tzd: tzdev);
291 struct mlxsw_thermal *thermal = tz->parent;
292 char mtmp_pl[MLXSW_REG_MTMP_LEN];
293 u16 sensor_index;
294 int err;
295
296 sensor_index = MLXSW_REG_MTMP_MODULE_INDEX_MIN + tz->module;
297 mlxsw_reg_mtmp_pack(payload: mtmp_pl, slot_index: tz->slot_index, sensor_index,
298 max_temp_enable: false, max_temp_reset: false);
299 err = mlxsw_reg_query(mlxsw_core: thermal->core, MLXSW_REG(mtmp), payload: mtmp_pl);
300 if (err)
301 return err;
302 mlxsw_reg_mtmp_unpack(payload: mtmp_pl, p_temp, NULL, NULL, NULL, NULL);
303 return 0;
304}
305
306static struct thermal_zone_device_ops mlxsw_thermal_module_ops = {
307 .bind = mlxsw_thermal_module_bind,
308 .unbind = mlxsw_thermal_module_unbind,
309 .get_temp = mlxsw_thermal_module_temp_get,
310};
311
312static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev,
313 int *p_temp)
314{
315 struct mlxsw_thermal_module *tz = thermal_zone_device_priv(tzd: tzdev);
316 struct mlxsw_thermal *thermal = tz->parent;
317 char mtmp_pl[MLXSW_REG_MTMP_LEN];
318 u16 index;
319 int temp;
320 int err;
321
322 index = MLXSW_REG_MTMP_GBOX_INDEX_MIN + tz->module;
323 mlxsw_reg_mtmp_pack(payload: mtmp_pl, slot_index: tz->slot_index, sensor_index: index, max_temp_enable: false, max_temp_reset: false);
324
325 err = mlxsw_reg_query(mlxsw_core: thermal->core, MLXSW_REG(mtmp), payload: mtmp_pl);
326 if (err)
327 return err;
328
329 mlxsw_reg_mtmp_unpack(payload: mtmp_pl, p_temp: &temp, NULL, NULL, NULL, NULL);
330
331 *p_temp = temp;
332 return 0;
333}
334
335static struct thermal_zone_device_ops mlxsw_thermal_gearbox_ops = {
336 .bind = mlxsw_thermal_module_bind,
337 .unbind = mlxsw_thermal_module_unbind,
338 .get_temp = mlxsw_thermal_gearbox_temp_get,
339};
340
341static int mlxsw_thermal_get_max_state(struct thermal_cooling_device *cdev,
342 unsigned long *p_state)
343{
344 *p_state = MLXSW_THERMAL_MAX_STATE;
345 return 0;
346}
347
348static int mlxsw_thermal_get_cur_state(struct thermal_cooling_device *cdev,
349 unsigned long *p_state)
350
351{
352 struct mlxsw_thermal *thermal = cdev->devdata;
353 struct device *dev = thermal->bus_info->dev;
354 char mfsc_pl[MLXSW_REG_MFSC_LEN];
355 int err, idx;
356 u8 duty;
357
358 idx = mlxsw_get_cooling_device_idx(thermal, cdev);
359 if (idx < 0)
360 return idx;
361
362 mlxsw_reg_mfsc_pack(payload: mfsc_pl, pwm: idx, pwm_duty_cycle: 0);
363 err = mlxsw_reg_query(mlxsw_core: thermal->core, MLXSW_REG(mfsc), payload: mfsc_pl);
364 if (err) {
365 dev_err(dev, "Failed to query PWM duty\n");
366 return err;
367 }
368
369 duty = mlxsw_reg_mfsc_pwm_duty_cycle_get(buf: mfsc_pl);
370 *p_state = mlxsw_duty_to_state(duty);
371 return 0;
372}
373
374static int mlxsw_thermal_set_cur_state(struct thermal_cooling_device *cdev,
375 unsigned long state)
376
377{
378 struct mlxsw_thermal *thermal = cdev->devdata;
379 struct device *dev = thermal->bus_info->dev;
380 char mfsc_pl[MLXSW_REG_MFSC_LEN];
381 int idx;
382 int err;
383
384 if (state > MLXSW_THERMAL_MAX_STATE)
385 return -EINVAL;
386
387 idx = mlxsw_get_cooling_device_idx(thermal, cdev);
388 if (idx < 0)
389 return idx;
390
391 /* Normalize the state to the valid speed range. */
392 state = max_t(unsigned long, MLXSW_THERMAL_MIN_STATE, state);
393 mlxsw_reg_mfsc_pack(payload: mfsc_pl, pwm: idx, pwm_duty_cycle: mlxsw_state_to_duty(state));
394 err = mlxsw_reg_write(mlxsw_core: thermal->core, MLXSW_REG(mfsc), payload: mfsc_pl);
395 if (err) {
396 dev_err(dev, "Failed to write PWM duty\n");
397 return err;
398 }
399 return 0;
400}
401
402static const struct thermal_cooling_device_ops mlxsw_cooling_ops = {
403 .get_max_state = mlxsw_thermal_get_max_state,
404 .get_cur_state = mlxsw_thermal_get_cur_state,
405 .set_cur_state = mlxsw_thermal_set_cur_state,
406};
407
408static int
409mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz)
410{
411 char tz_name[THERMAL_NAME_LENGTH];
412 int err;
413
414 if (module_tz->slot_index)
415 snprintf(buf: tz_name, size: sizeof(tz_name), fmt: "mlxsw-lc%d-module%d",
416 module_tz->slot_index, module_tz->module + 1);
417 else
418 snprintf(buf: tz_name, size: sizeof(tz_name), fmt: "mlxsw-module%d",
419 module_tz->module + 1);
420 module_tz->tzdev = thermal_zone_device_register_with_trips(type: tz_name,
421 trips: module_tz->trips,
422 MLXSW_THERMAL_NUM_TRIPS,
423 MLXSW_THERMAL_TRIP_MASK,
424 devdata: module_tz,
425 ops: &mlxsw_thermal_module_ops,
426 tzp: &mlxsw_thermal_params,
427 passive_delay: 0,
428 polling_delay: module_tz->parent->polling_delay);
429 if (IS_ERR(ptr: module_tz->tzdev)) {
430 err = PTR_ERR(ptr: module_tz->tzdev);
431 return err;
432 }
433
434 err = thermal_zone_device_enable(tz: module_tz->tzdev);
435 if (err)
436 thermal_zone_device_unregister(tz: module_tz->tzdev);
437
438 return err;
439}
440
441static void mlxsw_thermal_module_tz_fini(struct thermal_zone_device *tzdev)
442{
443 thermal_zone_device_unregister(tz: tzdev);
444}
445
446static void
447mlxsw_thermal_module_init(struct device *dev, struct mlxsw_core *core,
448 struct mlxsw_thermal *thermal,
449 struct mlxsw_thermal_area *area, u8 module)
450{
451 struct mlxsw_thermal_module *module_tz;
452
453 module_tz = &area->tz_module_arr[module];
454 /* Skip if parent is already set (case of port split). */
455 if (module_tz->parent)
456 return;
457 module_tz->module = module;
458 module_tz->slot_index = area->slot_index;
459 module_tz->parent = thermal;
460 BUILD_BUG_ON(ARRAY_SIZE(default_thermal_module_trips) !=
461 MLXSW_THERMAL_NUM_TRIPS);
462 memcpy(module_tz->trips, default_thermal_module_trips,
463 sizeof(thermal->trips));
464 memcpy(module_tz->cooling_states, default_cooling_states,
465 sizeof(thermal->cooling_states));
466}
467
468static void mlxsw_thermal_module_fini(struct mlxsw_thermal_module *module_tz)
469{
470 if (module_tz && module_tz->tzdev) {
471 mlxsw_thermal_module_tz_fini(tzdev: module_tz->tzdev);
472 module_tz->tzdev = NULL;
473 module_tz->parent = NULL;
474 }
475}
476
477static int
478mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core,
479 struct mlxsw_thermal *thermal,
480 struct mlxsw_thermal_area *area)
481{
482 struct mlxsw_thermal_module *module_tz;
483 char mgpir_pl[MLXSW_REG_MGPIR_LEN];
484 int i, err;
485
486 mlxsw_reg_mgpir_pack(payload: mgpir_pl, slot_index: area->slot_index);
487 err = mlxsw_reg_query(mlxsw_core: core, MLXSW_REG(mgpir), payload: mgpir_pl);
488 if (err)
489 return err;
490
491 mlxsw_reg_mgpir_unpack(payload: mgpir_pl, NULL, NULL, NULL,
492 num_of_modules: &area->tz_module_num, NULL);
493
494 /* For modular system module counter could be zero. */
495 if (!area->tz_module_num)
496 return 0;
497
498 area->tz_module_arr = kcalloc(n: area->tz_module_num,
499 size: sizeof(*area->tz_module_arr),
500 GFP_KERNEL);
501 if (!area->tz_module_arr)
502 return -ENOMEM;
503
504 for (i = 0; i < area->tz_module_num; i++)
505 mlxsw_thermal_module_init(dev, core, thermal, area, module: i);
506
507 for (i = 0; i < area->tz_module_num; i++) {
508 module_tz = &area->tz_module_arr[i];
509 if (!module_tz->parent)
510 continue;
511 err = mlxsw_thermal_module_tz_init(module_tz);
512 if (err)
513 goto err_thermal_module_tz_init;
514 }
515
516 return 0;
517
518err_thermal_module_tz_init:
519 for (i = area->tz_module_num - 1; i >= 0; i--)
520 mlxsw_thermal_module_fini(module_tz: &area->tz_module_arr[i]);
521 kfree(objp: area->tz_module_arr);
522 return err;
523}
524
525static void
526mlxsw_thermal_modules_fini(struct mlxsw_thermal *thermal,
527 struct mlxsw_thermal_area *area)
528{
529 int i;
530
531 for (i = area->tz_module_num - 1; i >= 0; i--)
532 mlxsw_thermal_module_fini(module_tz: &area->tz_module_arr[i]);
533 kfree(objp: area->tz_module_arr);
534}
535
536static int
537mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz)
538{
539 char tz_name[40];
540 int ret;
541
542 if (gearbox_tz->slot_index)
543 snprintf(buf: tz_name, size: sizeof(tz_name), fmt: "mlxsw-lc%d-gearbox%d",
544 gearbox_tz->slot_index, gearbox_tz->module + 1);
545 else
546 snprintf(buf: tz_name, size: sizeof(tz_name), fmt: "mlxsw-gearbox%d",
547 gearbox_tz->module + 1);
548 gearbox_tz->tzdev = thermal_zone_device_register_with_trips(type: tz_name,
549 trips: gearbox_tz->trips,
550 MLXSW_THERMAL_NUM_TRIPS,
551 MLXSW_THERMAL_TRIP_MASK,
552 devdata: gearbox_tz,
553 ops: &mlxsw_thermal_gearbox_ops,
554 tzp: &mlxsw_thermal_params, passive_delay: 0,
555 polling_delay: gearbox_tz->parent->polling_delay);
556 if (IS_ERR(ptr: gearbox_tz->tzdev))
557 return PTR_ERR(ptr: gearbox_tz->tzdev);
558
559 ret = thermal_zone_device_enable(tz: gearbox_tz->tzdev);
560 if (ret)
561 thermal_zone_device_unregister(tz: gearbox_tz->tzdev);
562
563 return ret;
564}
565
566static void
567mlxsw_thermal_gearbox_tz_fini(struct mlxsw_thermal_module *gearbox_tz)
568{
569 thermal_zone_device_unregister(tz: gearbox_tz->tzdev);
570}
571
572static int
573mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core,
574 struct mlxsw_thermal *thermal,
575 struct mlxsw_thermal_area *area)
576{
577 enum mlxsw_reg_mgpir_device_type device_type;
578 struct mlxsw_thermal_module *gearbox_tz;
579 char mgpir_pl[MLXSW_REG_MGPIR_LEN];
580 u8 gbox_num;
581 int i;
582 int err;
583
584 mlxsw_reg_mgpir_pack(payload: mgpir_pl, slot_index: area->slot_index);
585 err = mlxsw_reg_query(mlxsw_core: core, MLXSW_REG(mgpir), payload: mgpir_pl);
586 if (err)
587 return err;
588
589 mlxsw_reg_mgpir_unpack(payload: mgpir_pl, num_of_devices: &gbox_num, device_type: &device_type, NULL,
590 NULL, NULL);
591 if (device_type != MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE ||
592 !gbox_num)
593 return 0;
594
595 area->tz_gearbox_num = gbox_num;
596 area->tz_gearbox_arr = kcalloc(n: area->tz_gearbox_num,
597 size: sizeof(*area->tz_gearbox_arr),
598 GFP_KERNEL);
599 if (!area->tz_gearbox_arr)
600 return -ENOMEM;
601
602 for (i = 0; i < area->tz_gearbox_num; i++) {
603 gearbox_tz = &area->tz_gearbox_arr[i];
604 memcpy(gearbox_tz->trips, default_thermal_trips,
605 sizeof(thermal->trips));
606 memcpy(gearbox_tz->cooling_states, default_cooling_states,
607 sizeof(thermal->cooling_states));
608 gearbox_tz->module = i;
609 gearbox_tz->parent = thermal;
610 gearbox_tz->slot_index = area->slot_index;
611 err = mlxsw_thermal_gearbox_tz_init(gearbox_tz);
612 if (err)
613 goto err_thermal_gearbox_tz_init;
614 }
615
616 return 0;
617
618err_thermal_gearbox_tz_init:
619 for (i--; i >= 0; i--)
620 mlxsw_thermal_gearbox_tz_fini(gearbox_tz: &area->tz_gearbox_arr[i]);
621 kfree(objp: area->tz_gearbox_arr);
622 return err;
623}
624
625static void
626mlxsw_thermal_gearboxes_fini(struct mlxsw_thermal *thermal,
627 struct mlxsw_thermal_area *area)
628{
629 int i;
630
631 for (i = area->tz_gearbox_num - 1; i >= 0; i--)
632 mlxsw_thermal_gearbox_tz_fini(gearbox_tz: &area->tz_gearbox_arr[i]);
633 kfree(objp: area->tz_gearbox_arr);
634}
635
636static void
637mlxsw_thermal_got_active(struct mlxsw_core *mlxsw_core, u8 slot_index,
638 void *priv)
639{
640 struct mlxsw_thermal *thermal = priv;
641 struct mlxsw_thermal_area *linecard;
642 int err;
643
644 linecard = &thermal->line_cards[slot_index];
645
646 if (linecard->active)
647 return;
648
649 linecard->slot_index = slot_index;
650 err = mlxsw_thermal_modules_init(dev: thermal->bus_info->dev, core: thermal->core,
651 thermal, area: linecard);
652 if (err) {
653 dev_err(thermal->bus_info->dev, "Failed to configure thermal objects for line card modules in slot %d\n",
654 slot_index);
655 return;
656 }
657
658 err = mlxsw_thermal_gearboxes_init(dev: thermal->bus_info->dev,
659 core: thermal->core, thermal, area: linecard);
660 if (err) {
661 dev_err(thermal->bus_info->dev, "Failed to configure thermal objects for line card gearboxes in slot %d\n",
662 slot_index);
663 goto err_thermal_linecard_gearboxes_init;
664 }
665
666 linecard->active = true;
667
668 return;
669
670err_thermal_linecard_gearboxes_init:
671 mlxsw_thermal_modules_fini(thermal, area: linecard);
672}
673
674static void
675mlxsw_thermal_got_inactive(struct mlxsw_core *mlxsw_core, u8 slot_index,
676 void *priv)
677{
678 struct mlxsw_thermal *thermal = priv;
679 struct mlxsw_thermal_area *linecard;
680
681 linecard = &thermal->line_cards[slot_index];
682 if (!linecard->active)
683 return;
684 linecard->active = false;
685 mlxsw_thermal_gearboxes_fini(thermal, area: linecard);
686 mlxsw_thermal_modules_fini(thermal, area: linecard);
687}
688
689static struct mlxsw_linecards_event_ops mlxsw_thermal_event_ops = {
690 .got_active = mlxsw_thermal_got_active,
691 .got_inactive = mlxsw_thermal_got_inactive,
692};
693
694int mlxsw_thermal_init(struct mlxsw_core *core,
695 const struct mlxsw_bus_info *bus_info,
696 struct mlxsw_thermal **p_thermal)
697{
698 char mfcr_pl[MLXSW_REG_MFCR_LEN] = { 0 };
699 enum mlxsw_reg_mfcr_pwm_frequency freq;
700 struct device *dev = bus_info->dev;
701 char mgpir_pl[MLXSW_REG_MGPIR_LEN];
702 struct mlxsw_thermal *thermal;
703 u8 pwm_active, num_of_slots;
704 u16 tacho_active;
705 int err, i;
706
707 mlxsw_reg_mgpir_pack(payload: mgpir_pl, slot_index: 0);
708 err = mlxsw_reg_query(mlxsw_core: core, MLXSW_REG(mgpir), payload: mgpir_pl);
709 if (err)
710 return err;
711
712 mlxsw_reg_mgpir_unpack(payload: mgpir_pl, NULL, NULL, NULL, NULL,
713 num_of_slots: &num_of_slots);
714
715 thermal = kzalloc(struct_size(thermal, line_cards, num_of_slots + 1),
716 GFP_KERNEL);
717 if (!thermal)
718 return -ENOMEM;
719
720 thermal->core = core;
721 thermal->bus_info = bus_info;
722 memcpy(thermal->trips, default_thermal_trips, sizeof(thermal->trips));
723 memcpy(thermal->cooling_states, default_cooling_states, sizeof(thermal->cooling_states));
724 thermal->line_cards[0].slot_index = 0;
725
726 err = mlxsw_reg_query(mlxsw_core: thermal->core, MLXSW_REG(mfcr), payload: mfcr_pl);
727 if (err) {
728 dev_err(dev, "Failed to probe PWMs\n");
729 goto err_reg_query;
730 }
731 mlxsw_reg_mfcr_unpack(payload: mfcr_pl, p_pwm_frequency: &freq, p_tacho_active: &tacho_active, p_pwm_active: &pwm_active);
732
733 for (i = 0; i < MLXSW_MFCR_TACHOS_MAX; i++) {
734 if (tacho_active & BIT(i)) {
735 char mfsl_pl[MLXSW_REG_MFSL_LEN];
736
737 mlxsw_reg_mfsl_pack(payload: mfsl_pl, tacho: i, tach_min: 0, tach_max: 0);
738
739 /* We need to query the register to preserve maximum */
740 err = mlxsw_reg_query(mlxsw_core: thermal->core, MLXSW_REG(mfsl),
741 payload: mfsl_pl);
742 if (err)
743 goto err_reg_query;
744
745 /* set the minimal RPMs to 0 */
746 mlxsw_reg_mfsl_tach_min_set(buf: mfsl_pl, val: 0);
747 err = mlxsw_reg_write(mlxsw_core: thermal->core, MLXSW_REG(mfsl),
748 payload: mfsl_pl);
749 if (err)
750 goto err_reg_write;
751 }
752 }
753 for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++) {
754 if (pwm_active & BIT(i)) {
755 struct thermal_cooling_device *cdev;
756
757 cdev = thermal_cooling_device_register("mlxsw_fan",
758 thermal,
759 &mlxsw_cooling_ops);
760 if (IS_ERR(ptr: cdev)) {
761 err = PTR_ERR(ptr: cdev);
762 dev_err(dev, "Failed to register cooling device\n");
763 goto err_thermal_cooling_device_register;
764 }
765 thermal->cdevs[i] = cdev;
766 }
767 }
768
769 thermal->polling_delay = bus_info->low_frequency ?
770 MLXSW_THERMAL_SLOW_POLL_INT :
771 MLXSW_THERMAL_POLL_INT;
772
773 thermal->tzdev = thermal_zone_device_register_with_trips(type: "mlxsw",
774 trips: thermal->trips,
775 MLXSW_THERMAL_NUM_TRIPS,
776 MLXSW_THERMAL_TRIP_MASK,
777 devdata: thermal,
778 ops: &mlxsw_thermal_ops,
779 tzp: &mlxsw_thermal_params, passive_delay: 0,
780 polling_delay: thermal->polling_delay);
781 if (IS_ERR(ptr: thermal->tzdev)) {
782 err = PTR_ERR(ptr: thermal->tzdev);
783 dev_err(dev, "Failed to register thermal zone\n");
784 goto err_thermal_zone_device_register;
785 }
786
787 err = mlxsw_thermal_modules_init(dev, core, thermal,
788 area: &thermal->line_cards[0]);
789 if (err)
790 goto err_thermal_modules_init;
791
792 err = mlxsw_thermal_gearboxes_init(dev, core, thermal,
793 area: &thermal->line_cards[0]);
794 if (err)
795 goto err_thermal_gearboxes_init;
796
797 err = mlxsw_linecards_event_ops_register(mlxsw_core: core,
798 ops: &mlxsw_thermal_event_ops,
799 priv: thermal);
800 if (err)
801 goto err_linecards_event_ops_register;
802
803 err = thermal_zone_device_enable(tz: thermal->tzdev);
804 if (err)
805 goto err_thermal_zone_device_enable;
806
807 thermal->line_cards[0].active = true;
808 *p_thermal = thermal;
809 return 0;
810
811err_thermal_zone_device_enable:
812 mlxsw_linecards_event_ops_unregister(mlxsw_core: thermal->core,
813 ops: &mlxsw_thermal_event_ops,
814 priv: thermal);
815err_linecards_event_ops_register:
816 mlxsw_thermal_gearboxes_fini(thermal, area: &thermal->line_cards[0]);
817err_thermal_gearboxes_init:
818 mlxsw_thermal_modules_fini(thermal, area: &thermal->line_cards[0]);
819err_thermal_modules_init:
820 if (thermal->tzdev) {
821 thermal_zone_device_unregister(tz: thermal->tzdev);
822 thermal->tzdev = NULL;
823 }
824err_thermal_zone_device_register:
825err_thermal_cooling_device_register:
826 for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++)
827 if (thermal->cdevs[i])
828 thermal_cooling_device_unregister(thermal->cdevs[i]);
829err_reg_write:
830err_reg_query:
831 kfree(objp: thermal);
832 return err;
833}
834
835void mlxsw_thermal_fini(struct mlxsw_thermal *thermal)
836{
837 int i;
838
839 thermal->line_cards[0].active = false;
840 mlxsw_linecards_event_ops_unregister(mlxsw_core: thermal->core,
841 ops: &mlxsw_thermal_event_ops,
842 priv: thermal);
843 mlxsw_thermal_gearboxes_fini(thermal, area: &thermal->line_cards[0]);
844 mlxsw_thermal_modules_fini(thermal, area: &thermal->line_cards[0]);
845 if (thermal->tzdev) {
846 thermal_zone_device_unregister(tz: thermal->tzdev);
847 thermal->tzdev = NULL;
848 }
849
850 for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++) {
851 if (thermal->cdevs[i]) {
852 thermal_cooling_device_unregister(thermal->cdevs[i]);
853 thermal->cdevs[i] = NULL;
854 }
855 }
856
857 kfree(objp: thermal);
858}
859

source code of linux/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c