forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-01-31 f9004dbfff8a3fbbd7e2a88c8a4327c7f2f8e5b2
kernel/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
....@@ -9,17 +9,41 @@
99 #include <linux/sysfs.h>
1010 #include <linux/thermal.h>
1111 #include <linux/err.h>
12
+#include <linux/sfp.h>
1213
1314 #include "core.h"
15
+#include "core_env.h"
1416
1517 #define MLXSW_THERMAL_POLL_INT 1000 /* ms */
16
-#define MLXSW_THERMAL_MAX_TEMP 110000 /* 110C */
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_ASIC_TEMP_CRIT 140000 /* 140C */
23
+#define MLXSW_THERMAL_HYSTERESIS_TEMP 5000 /* 5C */
24
+#define MLXSW_THERMAL_MODULE_TEMP_SHIFT (MLXSW_THERMAL_HYSTERESIS_TEMP * 2)
25
+#define MLXSW_THERMAL_ZONE_MAX_NAME 16
26
+#define MLXSW_THERMAL_TEMP_SCORE_MAX GENMASK(31, 0)
1727 #define MLXSW_THERMAL_MAX_STATE 10
28
+#define MLXSW_THERMAL_MIN_STATE 2
1829 #define MLXSW_THERMAL_MAX_DUTY 255
30
+
31
+/* External cooling devices, allowed for binding to mlxsw thermal zones. */
32
+static char * const mlxsw_thermal_external_allowed_cdev[] = {
33
+ "mlxreg_fan",
34
+};
35
+
36
+enum mlxsw_thermal_trips {
37
+ MLXSW_THERMAL_TEMP_TRIP_NORM,
38
+ MLXSW_THERMAL_TEMP_TRIP_HIGH,
39
+ MLXSW_THERMAL_TEMP_TRIP_HOT,
40
+ MLXSW_THERMAL_TEMP_TRIP_CRIT,
41
+};
1942
2043 struct mlxsw_thermal_trip {
2144 int type;
2245 int temp;
46
+ int hyst;
2347 int min_state;
2448 int max_state;
2549 };
....@@ -27,32 +51,29 @@
2751 static const struct mlxsw_thermal_trip default_thermal_trips[] = {
2852 { /* In range - 0-40% PWM */
2953 .type = THERMAL_TRIP_ACTIVE,
30
- .temp = 75000,
54
+ .temp = MLXSW_THERMAL_ASIC_TEMP_NORM,
55
+ .hyst = MLXSW_THERMAL_HYSTERESIS_TEMP,
3156 .min_state = 0,
3257 .max_state = (4 * MLXSW_THERMAL_MAX_STATE) / 10,
3358 },
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
- },
4059 {
41
- /* Very high - 100% PWM */
60
+ /* In range - 40-100% PWM */
4261 .type = THERMAL_TRIP_ACTIVE,
43
- .temp = 85000,
44
- .min_state = MLXSW_THERMAL_MAX_STATE,
62
+ .temp = MLXSW_THERMAL_ASIC_TEMP_HIGH,
63
+ .hyst = MLXSW_THERMAL_HYSTERESIS_TEMP,
64
+ .min_state = (4 * MLXSW_THERMAL_MAX_STATE) / 10,
4565 .max_state = MLXSW_THERMAL_MAX_STATE,
4666 },
4767 { /* Warning */
4868 .type = THERMAL_TRIP_HOT,
49
- .temp = 105000,
69
+ .temp = MLXSW_THERMAL_ASIC_TEMP_HOT,
70
+ .hyst = MLXSW_THERMAL_HYSTERESIS_TEMP,
5071 .min_state = MLXSW_THERMAL_MAX_STATE,
5172 .max_state = MLXSW_THERMAL_MAX_STATE,
5273 },
5374 { /* Critical - soft poweroff */
5475 .type = THERMAL_TRIP_CRITICAL,
55
- .temp = MLXSW_THERMAL_MAX_TEMP,
76
+ .temp = MLXSW_THERMAL_ASIC_TEMP_CRIT,
5677 .min_state = MLXSW_THERMAL_MAX_STATE,
5778 .max_state = MLXSW_THERMAL_MAX_STATE,
5879 }
....@@ -63,13 +84,29 @@
6384 /* Make sure all trips are writable */
6485 #define MLXSW_THERMAL_TRIP_MASK (BIT(MLXSW_THERMAL_NUM_TRIPS) - 1)
6586
87
+struct mlxsw_thermal;
88
+
89
+struct mlxsw_thermal_module {
90
+ struct mlxsw_thermal *parent;
91
+ struct thermal_zone_device *tzdev;
92
+ struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
93
+ int module; /* Module or gearbox number */
94
+};
95
+
6696 struct mlxsw_thermal {
6797 struct mlxsw_core *core;
6898 const struct mlxsw_bus_info *bus_info;
6999 struct thermal_zone_device *tzdev;
100
+ int polling_delay;
70101 struct thermal_cooling_device *cdevs[MLXSW_MFCR_PWMS_MAX];
102
+ u8 cooling_levels[MLXSW_THERMAL_MAX_STATE + 1];
71103 struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
72
- enum thermal_device_mode mode;
104
+ struct mlxsw_thermal_module *tz_module_arr;
105
+ u8 tz_module_num;
106
+ struct mlxsw_thermal_module *tz_gearbox_arr;
107
+ u8 tz_gearbox_num;
108
+ unsigned int tz_highest_score;
109
+ struct thermal_zone_device *tz_highest_dev;
73110 };
74111
75112 static inline u8 mlxsw_state_to_duty(int state)
....@@ -93,7 +130,96 @@
93130 if (thermal->cdevs[i] == cdev)
94131 return i;
95132
133
+ /* Allow mlxsw thermal zone binding to an external cooling device */
134
+ for (i = 0; i < ARRAY_SIZE(mlxsw_thermal_external_allowed_cdev); i++) {
135
+ if (strnstr(cdev->type, mlxsw_thermal_external_allowed_cdev[i],
136
+ sizeof(cdev->type)))
137
+ return 0;
138
+ }
139
+
96140 return -ENODEV;
141
+}
142
+
143
+static void
144
+mlxsw_thermal_module_trips_reset(struct mlxsw_thermal_module *tz)
145
+{
146
+ tz->trips[MLXSW_THERMAL_TEMP_TRIP_NORM].temp = 0;
147
+ tz->trips[MLXSW_THERMAL_TEMP_TRIP_HIGH].temp = 0;
148
+ tz->trips[MLXSW_THERMAL_TEMP_TRIP_HOT].temp = 0;
149
+ tz->trips[MLXSW_THERMAL_TEMP_TRIP_CRIT].temp = 0;
150
+}
151
+
152
+static int
153
+mlxsw_thermal_module_trips_update(struct device *dev, struct mlxsw_core *core,
154
+ struct mlxsw_thermal_module *tz)
155
+{
156
+ int crit_temp, emerg_temp;
157
+ int err;
158
+
159
+ err = mlxsw_env_module_temp_thresholds_get(core, tz->module,
160
+ SFP_TEMP_HIGH_WARN,
161
+ &crit_temp);
162
+ if (err)
163
+ return err;
164
+
165
+ err = mlxsw_env_module_temp_thresholds_get(core, tz->module,
166
+ SFP_TEMP_HIGH_ALARM,
167
+ &emerg_temp);
168
+ if (err)
169
+ return err;
170
+
171
+ if (crit_temp > emerg_temp) {
172
+ dev_warn(dev, "%s : Critical threshold %d is above emergency threshold %d\n",
173
+ tz->tzdev->type, crit_temp, emerg_temp);
174
+ return 0;
175
+ }
176
+
177
+ /* According to the system thermal requirements, the thermal zones are
178
+ * defined with four trip points. The critical and emergency
179
+ * temperature thresholds, provided by QSFP module are set as "active"
180
+ * and "hot" trip points, "normal" and "critical" trip points are
181
+ * derived from "active" and "hot" by subtracting or adding double
182
+ * hysteresis value.
183
+ */
184
+ if (crit_temp >= MLXSW_THERMAL_MODULE_TEMP_SHIFT)
185
+ tz->trips[MLXSW_THERMAL_TEMP_TRIP_NORM].temp = crit_temp -
186
+ MLXSW_THERMAL_MODULE_TEMP_SHIFT;
187
+ else
188
+ tz->trips[MLXSW_THERMAL_TEMP_TRIP_NORM].temp = crit_temp;
189
+ tz->trips[MLXSW_THERMAL_TEMP_TRIP_HIGH].temp = crit_temp;
190
+ tz->trips[MLXSW_THERMAL_TEMP_TRIP_HOT].temp = emerg_temp;
191
+ tz->trips[MLXSW_THERMAL_TEMP_TRIP_CRIT].temp = emerg_temp +
192
+ MLXSW_THERMAL_MODULE_TEMP_SHIFT;
193
+
194
+ return 0;
195
+}
196
+
197
+static void mlxsw_thermal_tz_score_update(struct mlxsw_thermal *thermal,
198
+ struct thermal_zone_device *tzdev,
199
+ struct mlxsw_thermal_trip *trips,
200
+ int temp)
201
+{
202
+ struct mlxsw_thermal_trip *trip = trips;
203
+ unsigned int score, delta, i, shift = 1;
204
+
205
+ /* Calculate thermal zone score, if temperature is above the critical
206
+ * threshold score is set to MLXSW_THERMAL_TEMP_SCORE_MAX.
207
+ */
208
+ score = MLXSW_THERMAL_TEMP_SCORE_MAX;
209
+ for (i = MLXSW_THERMAL_TEMP_TRIP_NORM; i < MLXSW_THERMAL_NUM_TRIPS;
210
+ i++, trip++) {
211
+ if (temp < trip->temp) {
212
+ delta = DIV_ROUND_CLOSEST(temp, trip->temp - temp);
213
+ score = delta * shift;
214
+ break;
215
+ }
216
+ shift *= 256;
217
+ }
218
+
219
+ if (score > thermal->tz_highest_score) {
220
+ thermal->tz_highest_score = score;
221
+ thermal->tz_highest_dev = tzdev;
222
+ }
97223 }
98224
99225 static int mlxsw_thermal_bind(struct thermal_zone_device *tzdev,
....@@ -144,43 +270,13 @@
144270 return 0;
145271 }
146272
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
-
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
-
177273 static int mlxsw_thermal_get_temp(struct thermal_zone_device *tzdev,
178274 int *p_temp)
179275 {
180276 struct mlxsw_thermal *thermal = tzdev->devdata;
181277 struct device *dev = thermal->bus_info->dev;
182278 char mtmp_pl[MLXSW_REG_MTMP_LEN];
183
- unsigned int temp;
279
+ int temp;
184280 int err;
185281
186282 mlxsw_reg_mtmp_pack(mtmp_pl, 0, false, false);
....@@ -191,8 +287,11 @@
191287 return err;
192288 }
193289 mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL);
290
+ if (temp > 0)
291
+ mlxsw_thermal_tz_score_update(thermal, tzdev, thermal->trips,
292
+ temp);
194293
195
- *p_temp = (int) temp;
294
+ *p_temp = temp;
196295 return 0;
197296 }
198297
....@@ -227,22 +326,265 @@
227326 struct mlxsw_thermal *thermal = tzdev->devdata;
228327
229328 if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS ||
230
- temp > MLXSW_THERMAL_MAX_TEMP)
329
+ temp > MLXSW_THERMAL_ASIC_TEMP_CRIT)
231330 return -EINVAL;
232331
233332 thermal->trips[trip].temp = temp;
234333 return 0;
235334 }
236335
336
+static int mlxsw_thermal_get_trip_hyst(struct thermal_zone_device *tzdev,
337
+ int trip, int *p_hyst)
338
+{
339
+ struct mlxsw_thermal *thermal = tzdev->devdata;
340
+
341
+ *p_hyst = thermal->trips[trip].hyst;
342
+ return 0;
343
+}
344
+
345
+static int mlxsw_thermal_set_trip_hyst(struct thermal_zone_device *tzdev,
346
+ int trip, int hyst)
347
+{
348
+ struct mlxsw_thermal *thermal = tzdev->devdata;
349
+
350
+ thermal->trips[trip].hyst = hyst;
351
+ return 0;
352
+}
353
+
354
+static int mlxsw_thermal_trend_get(struct thermal_zone_device *tzdev,
355
+ int trip, enum thermal_trend *trend)
356
+{
357
+ struct mlxsw_thermal *thermal = tzdev->devdata;
358
+
359
+ if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
360
+ return -EINVAL;
361
+
362
+ if (tzdev == thermal->tz_highest_dev)
363
+ return 1;
364
+
365
+ *trend = THERMAL_TREND_STABLE;
366
+ return 0;
367
+}
368
+
237369 static struct thermal_zone_device_ops mlxsw_thermal_ops = {
238370 .bind = mlxsw_thermal_bind,
239371 .unbind = mlxsw_thermal_unbind,
240
- .get_mode = mlxsw_thermal_get_mode,
241
- .set_mode = mlxsw_thermal_set_mode,
242372 .get_temp = mlxsw_thermal_get_temp,
243373 .get_trip_type = mlxsw_thermal_get_trip_type,
244374 .get_trip_temp = mlxsw_thermal_get_trip_temp,
245375 .set_trip_temp = mlxsw_thermal_set_trip_temp,
376
+ .get_trip_hyst = mlxsw_thermal_get_trip_hyst,
377
+ .set_trip_hyst = mlxsw_thermal_set_trip_hyst,
378
+ .get_trend = mlxsw_thermal_trend_get,
379
+};
380
+
381
+static int mlxsw_thermal_module_bind(struct thermal_zone_device *tzdev,
382
+ struct thermal_cooling_device *cdev)
383
+{
384
+ struct mlxsw_thermal_module *tz = tzdev->devdata;
385
+ struct mlxsw_thermal *thermal = tz->parent;
386
+ int i, j, err;
387
+
388
+ /* If the cooling device is one of ours bind it */
389
+ if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0)
390
+ return 0;
391
+
392
+ for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) {
393
+ const struct mlxsw_thermal_trip *trip = &tz->trips[i];
394
+
395
+ err = thermal_zone_bind_cooling_device(tzdev, i, cdev,
396
+ trip->max_state,
397
+ trip->min_state,
398
+ THERMAL_WEIGHT_DEFAULT);
399
+ if (err < 0)
400
+ goto err_bind_cooling_device;
401
+ }
402
+ return 0;
403
+
404
+err_bind_cooling_device:
405
+ for (j = i - 1; j >= 0; j--)
406
+ thermal_zone_unbind_cooling_device(tzdev, j, cdev);
407
+ return err;
408
+}
409
+
410
+static int mlxsw_thermal_module_unbind(struct thermal_zone_device *tzdev,
411
+ struct thermal_cooling_device *cdev)
412
+{
413
+ struct mlxsw_thermal_module *tz = tzdev->devdata;
414
+ struct mlxsw_thermal *thermal = tz->parent;
415
+ int i;
416
+ int err;
417
+
418
+ /* If the cooling device is one of ours unbind it */
419
+ if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0)
420
+ return 0;
421
+
422
+ for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) {
423
+ err = thermal_zone_unbind_cooling_device(tzdev, i, cdev);
424
+ WARN_ON(err);
425
+ }
426
+ return err;
427
+}
428
+
429
+static int mlxsw_thermal_module_temp_get(struct thermal_zone_device *tzdev,
430
+ int *p_temp)
431
+{
432
+ struct mlxsw_thermal_module *tz = tzdev->devdata;
433
+ struct mlxsw_thermal *thermal = tz->parent;
434
+ struct device *dev = thermal->bus_info->dev;
435
+ char mtmp_pl[MLXSW_REG_MTMP_LEN];
436
+ int temp;
437
+ int err;
438
+
439
+ /* Read module temperature. */
440
+ mlxsw_reg_mtmp_pack(mtmp_pl, MLXSW_REG_MTMP_MODULE_INDEX_MIN +
441
+ tz->module, false, false);
442
+ err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl);
443
+ if (err) {
444
+ /* Do not return error - in case of broken module's sensor
445
+ * it will cause error message flooding.
446
+ */
447
+ temp = 0;
448
+ *p_temp = (int) temp;
449
+ return 0;
450
+ }
451
+ mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL);
452
+ *p_temp = temp;
453
+
454
+ if (!temp)
455
+ return 0;
456
+
457
+ /* Update trip points. */
458
+ err = mlxsw_thermal_module_trips_update(dev, thermal->core, tz);
459
+ if (!err && temp > 0)
460
+ mlxsw_thermal_tz_score_update(thermal, tzdev, tz->trips, temp);
461
+
462
+ return 0;
463
+}
464
+
465
+static int
466
+mlxsw_thermal_module_trip_type_get(struct thermal_zone_device *tzdev, int trip,
467
+ enum thermal_trip_type *p_type)
468
+{
469
+ struct mlxsw_thermal_module *tz = tzdev->devdata;
470
+
471
+ if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
472
+ return -EINVAL;
473
+
474
+ *p_type = tz->trips[trip].type;
475
+ return 0;
476
+}
477
+
478
+static int
479
+mlxsw_thermal_module_trip_temp_get(struct thermal_zone_device *tzdev,
480
+ int trip, int *p_temp)
481
+{
482
+ struct mlxsw_thermal_module *tz = tzdev->devdata;
483
+
484
+ if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
485
+ return -EINVAL;
486
+
487
+ *p_temp = tz->trips[trip].temp;
488
+ return 0;
489
+}
490
+
491
+static int
492
+mlxsw_thermal_module_trip_temp_set(struct thermal_zone_device *tzdev,
493
+ int trip, int temp)
494
+{
495
+ struct mlxsw_thermal_module *tz = tzdev->devdata;
496
+
497
+ if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS ||
498
+ temp > tz->trips[MLXSW_THERMAL_TEMP_TRIP_CRIT].temp)
499
+ return -EINVAL;
500
+
501
+ tz->trips[trip].temp = temp;
502
+ return 0;
503
+}
504
+
505
+static int
506
+mlxsw_thermal_module_trip_hyst_get(struct thermal_zone_device *tzdev, int trip,
507
+ int *p_hyst)
508
+{
509
+ struct mlxsw_thermal_module *tz = tzdev->devdata;
510
+
511
+ *p_hyst = tz->trips[trip].hyst;
512
+ return 0;
513
+}
514
+
515
+static int
516
+mlxsw_thermal_module_trip_hyst_set(struct thermal_zone_device *tzdev, int trip,
517
+ int hyst)
518
+{
519
+ struct mlxsw_thermal_module *tz = tzdev->devdata;
520
+
521
+ tz->trips[trip].hyst = hyst;
522
+ return 0;
523
+}
524
+
525
+static int mlxsw_thermal_module_trend_get(struct thermal_zone_device *tzdev,
526
+ int trip, enum thermal_trend *trend)
527
+{
528
+ struct mlxsw_thermal_module *tz = tzdev->devdata;
529
+ struct mlxsw_thermal *thermal = tz->parent;
530
+
531
+ if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
532
+ return -EINVAL;
533
+
534
+ if (tzdev == thermal->tz_highest_dev)
535
+ return 1;
536
+
537
+ *trend = THERMAL_TREND_STABLE;
538
+ return 0;
539
+}
540
+
541
+static struct thermal_zone_device_ops mlxsw_thermal_module_ops = {
542
+ .bind = mlxsw_thermal_module_bind,
543
+ .unbind = mlxsw_thermal_module_unbind,
544
+ .get_temp = mlxsw_thermal_module_temp_get,
545
+ .get_trip_type = mlxsw_thermal_module_trip_type_get,
546
+ .get_trip_temp = mlxsw_thermal_module_trip_temp_get,
547
+ .set_trip_temp = mlxsw_thermal_module_trip_temp_set,
548
+ .get_trip_hyst = mlxsw_thermal_module_trip_hyst_get,
549
+ .set_trip_hyst = mlxsw_thermal_module_trip_hyst_set,
550
+ .get_trend = mlxsw_thermal_module_trend_get,
551
+};
552
+
553
+static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev,
554
+ int *p_temp)
555
+{
556
+ struct mlxsw_thermal_module *tz = tzdev->devdata;
557
+ struct mlxsw_thermal *thermal = tz->parent;
558
+ char mtmp_pl[MLXSW_REG_MTMP_LEN];
559
+ u16 index;
560
+ int temp;
561
+ int err;
562
+
563
+ index = MLXSW_REG_MTMP_GBOX_INDEX_MIN + tz->module;
564
+ mlxsw_reg_mtmp_pack(mtmp_pl, index, false, false);
565
+
566
+ err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl);
567
+ if (err)
568
+ return err;
569
+
570
+ mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL);
571
+ if (temp > 0)
572
+ mlxsw_thermal_tz_score_update(thermal, tzdev, tz->trips, temp);
573
+
574
+ *p_temp = temp;
575
+ return 0;
576
+}
577
+
578
+static struct thermal_zone_device_ops mlxsw_thermal_gearbox_ops = {
579
+ .bind = mlxsw_thermal_module_bind,
580
+ .unbind = mlxsw_thermal_module_unbind,
581
+ .get_temp = mlxsw_thermal_gearbox_temp_get,
582
+ .get_trip_type = mlxsw_thermal_module_trip_type_get,
583
+ .get_trip_temp = mlxsw_thermal_module_trip_temp_get,
584
+ .set_trip_temp = mlxsw_thermal_module_trip_temp_set,
585
+ .get_trip_hyst = mlxsw_thermal_module_trip_hyst_get,
586
+ .set_trip_hyst = mlxsw_thermal_module_trip_hyst_set,
587
+ .get_trend = mlxsw_thermal_module_trend_get,
246588 };
247589
248590 static int mlxsw_thermal_get_max_state(struct thermal_cooling_device *cdev,
....@@ -285,12 +627,18 @@
285627 struct mlxsw_thermal *thermal = cdev->devdata;
286628 struct device *dev = thermal->bus_info->dev;
287629 char mfsc_pl[MLXSW_REG_MFSC_LEN];
288
- int err, idx;
630
+ int idx;
631
+ int err;
632
+
633
+ if (state > MLXSW_THERMAL_MAX_STATE)
634
+ return -EINVAL;
289635
290636 idx = mlxsw_get_cooling_device_idx(thermal, cdev);
291637 if (idx < 0)
292638 return idx;
293639
640
+ /* Normalize the state to the valid speed range. */
641
+ state = thermal->cooling_levels[state];
294642 mlxsw_reg_mfsc_pack(mfsc_pl, idx, mlxsw_state_to_duty(state));
295643 err = mlxsw_reg_write(thermal->core, MLXSW_REG(mfsc), mfsc_pl);
296644 if (err) {
....@@ -305,6 +653,225 @@
305653 .get_cur_state = mlxsw_thermal_get_cur_state,
306654 .set_cur_state = mlxsw_thermal_set_cur_state,
307655 };
656
+
657
+static int
658
+mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz)
659
+{
660
+ char tz_name[MLXSW_THERMAL_ZONE_MAX_NAME];
661
+ int err;
662
+
663
+ snprintf(tz_name, sizeof(tz_name), "mlxsw-module%d",
664
+ module_tz->module + 1);
665
+ module_tz->tzdev = thermal_zone_device_register(tz_name,
666
+ MLXSW_THERMAL_NUM_TRIPS,
667
+ MLXSW_THERMAL_TRIP_MASK,
668
+ module_tz,
669
+ &mlxsw_thermal_module_ops,
670
+ NULL, 0,
671
+ module_tz->parent->polling_delay);
672
+ if (IS_ERR(module_tz->tzdev)) {
673
+ err = PTR_ERR(module_tz->tzdev);
674
+ return err;
675
+ }
676
+
677
+ err = thermal_zone_device_enable(module_tz->tzdev);
678
+ if (err)
679
+ thermal_zone_device_unregister(module_tz->tzdev);
680
+
681
+ return err;
682
+}
683
+
684
+static void mlxsw_thermal_module_tz_fini(struct thermal_zone_device *tzdev)
685
+{
686
+ thermal_zone_device_unregister(tzdev);
687
+}
688
+
689
+static int
690
+mlxsw_thermal_module_init(struct device *dev, struct mlxsw_core *core,
691
+ struct mlxsw_thermal *thermal, u8 module)
692
+{
693
+ struct mlxsw_thermal_module *module_tz;
694
+
695
+ module_tz = &thermal->tz_module_arr[module];
696
+ /* Skip if parent is already set (case of port split). */
697
+ if (module_tz->parent)
698
+ return 0;
699
+ module_tz->module = module;
700
+ module_tz->parent = thermal;
701
+ memcpy(module_tz->trips, default_thermal_trips,
702
+ sizeof(thermal->trips));
703
+ /* Initialize all trip point. */
704
+ mlxsw_thermal_module_trips_reset(module_tz);
705
+ /* Update trip point according to the module data. */
706
+ return mlxsw_thermal_module_trips_update(dev, core, module_tz);
707
+}
708
+
709
+static void mlxsw_thermal_module_fini(struct mlxsw_thermal_module *module_tz)
710
+{
711
+ if (module_tz && module_tz->tzdev) {
712
+ mlxsw_thermal_module_tz_fini(module_tz->tzdev);
713
+ module_tz->tzdev = NULL;
714
+ module_tz->parent = NULL;
715
+ }
716
+}
717
+
718
+static int
719
+mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core,
720
+ struct mlxsw_thermal *thermal)
721
+{
722
+ struct mlxsw_thermal_module *module_tz;
723
+ char mgpir_pl[MLXSW_REG_MGPIR_LEN];
724
+ int i, err;
725
+
726
+ if (!mlxsw_core_res_query_enabled(core))
727
+ return 0;
728
+
729
+ mlxsw_reg_mgpir_pack(mgpir_pl);
730
+ err = mlxsw_reg_query(core, MLXSW_REG(mgpir), mgpir_pl);
731
+ if (err)
732
+ return err;
733
+
734
+ mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL,
735
+ &thermal->tz_module_num);
736
+
737
+ thermal->tz_module_arr = kcalloc(thermal->tz_module_num,
738
+ sizeof(*thermal->tz_module_arr),
739
+ GFP_KERNEL);
740
+ if (!thermal->tz_module_arr)
741
+ return -ENOMEM;
742
+
743
+ for (i = 0; i < thermal->tz_module_num; i++) {
744
+ err = mlxsw_thermal_module_init(dev, core, thermal, i);
745
+ if (err)
746
+ goto err_unreg_tz_module_arr;
747
+ }
748
+
749
+ for (i = 0; i < thermal->tz_module_num; i++) {
750
+ module_tz = &thermal->tz_module_arr[i];
751
+ if (!module_tz->parent)
752
+ continue;
753
+ err = mlxsw_thermal_module_tz_init(module_tz);
754
+ if (err)
755
+ goto err_unreg_tz_module_arr;
756
+ }
757
+
758
+ return 0;
759
+
760
+err_unreg_tz_module_arr:
761
+ for (i = thermal->tz_module_num - 1; i >= 0; i--)
762
+ mlxsw_thermal_module_fini(&thermal->tz_module_arr[i]);
763
+ kfree(thermal->tz_module_arr);
764
+ return err;
765
+}
766
+
767
+static void
768
+mlxsw_thermal_modules_fini(struct mlxsw_thermal *thermal)
769
+{
770
+ int i;
771
+
772
+ if (!mlxsw_core_res_query_enabled(thermal->core))
773
+ return;
774
+
775
+ for (i = thermal->tz_module_num - 1; i >= 0; i--)
776
+ mlxsw_thermal_module_fini(&thermal->tz_module_arr[i]);
777
+ kfree(thermal->tz_module_arr);
778
+}
779
+
780
+static int
781
+mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz)
782
+{
783
+ char tz_name[MLXSW_THERMAL_ZONE_MAX_NAME];
784
+ int ret;
785
+
786
+ snprintf(tz_name, sizeof(tz_name), "mlxsw-gearbox%d",
787
+ gearbox_tz->module + 1);
788
+ gearbox_tz->tzdev = thermal_zone_device_register(tz_name,
789
+ MLXSW_THERMAL_NUM_TRIPS,
790
+ MLXSW_THERMAL_TRIP_MASK,
791
+ gearbox_tz,
792
+ &mlxsw_thermal_gearbox_ops,
793
+ NULL, 0,
794
+ gearbox_tz->parent->polling_delay);
795
+ if (IS_ERR(gearbox_tz->tzdev))
796
+ return PTR_ERR(gearbox_tz->tzdev);
797
+
798
+ ret = thermal_zone_device_enable(gearbox_tz->tzdev);
799
+ if (ret)
800
+ thermal_zone_device_unregister(gearbox_tz->tzdev);
801
+
802
+ return ret;
803
+}
804
+
805
+static void
806
+mlxsw_thermal_gearbox_tz_fini(struct mlxsw_thermal_module *gearbox_tz)
807
+{
808
+ thermal_zone_device_unregister(gearbox_tz->tzdev);
809
+}
810
+
811
+static int
812
+mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core,
813
+ struct mlxsw_thermal *thermal)
814
+{
815
+ enum mlxsw_reg_mgpir_device_type device_type;
816
+ struct mlxsw_thermal_module *gearbox_tz;
817
+ char mgpir_pl[MLXSW_REG_MGPIR_LEN];
818
+ u8 gbox_num;
819
+ int i;
820
+ int err;
821
+
822
+ if (!mlxsw_core_res_query_enabled(core))
823
+ return 0;
824
+
825
+ mlxsw_reg_mgpir_pack(mgpir_pl);
826
+ err = mlxsw_reg_query(core, MLXSW_REG(mgpir), mgpir_pl);
827
+ if (err)
828
+ return err;
829
+
830
+ mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, &device_type, NULL,
831
+ NULL);
832
+ if (device_type != MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE ||
833
+ !gbox_num)
834
+ return 0;
835
+
836
+ thermal->tz_gearbox_num = gbox_num;
837
+ thermal->tz_gearbox_arr = kcalloc(thermal->tz_gearbox_num,
838
+ sizeof(*thermal->tz_gearbox_arr),
839
+ GFP_KERNEL);
840
+ if (!thermal->tz_gearbox_arr)
841
+ return -ENOMEM;
842
+
843
+ for (i = 0; i < thermal->tz_gearbox_num; i++) {
844
+ gearbox_tz = &thermal->tz_gearbox_arr[i];
845
+ memcpy(gearbox_tz->trips, default_thermal_trips,
846
+ sizeof(thermal->trips));
847
+ gearbox_tz->module = i;
848
+ gearbox_tz->parent = thermal;
849
+ err = mlxsw_thermal_gearbox_tz_init(gearbox_tz);
850
+ if (err)
851
+ goto err_unreg_tz_gearbox;
852
+ }
853
+
854
+ return 0;
855
+
856
+err_unreg_tz_gearbox:
857
+ for (i--; i >= 0; i--)
858
+ mlxsw_thermal_gearbox_tz_fini(&thermal->tz_gearbox_arr[i]);
859
+ kfree(thermal->tz_gearbox_arr);
860
+ return err;
861
+}
862
+
863
+static void
864
+mlxsw_thermal_gearboxes_fini(struct mlxsw_thermal *thermal)
865
+{
866
+ int i;
867
+
868
+ if (!mlxsw_core_res_query_enabled(thermal->core))
869
+ return;
870
+
871
+ for (i = thermal->tz_gearbox_num - 1; i >= 0; i--)
872
+ mlxsw_thermal_gearbox_tz_fini(&thermal->tz_gearbox_arr[i]);
873
+ kfree(thermal->tz_gearbox_arr);
874
+}
308875
309876 int mlxsw_thermal_init(struct mlxsw_core *core,
310877 const struct mlxsw_bus_info *bus_info,
....@@ -358,8 +925,9 @@
358925 if (pwm_active & BIT(i)) {
359926 struct thermal_cooling_device *cdev;
360927
361
- cdev = thermal_cooling_device_register("Fan", thermal,
362
- &mlxsw_cooling_ops);
928
+ cdev = thermal_cooling_device_register("mlxsw_fan",
929
+ thermal,
930
+ &mlxsw_cooling_ops);
363931 if (IS_ERR(cdev)) {
364932 err = PTR_ERR(cdev);
365933 dev_err(dev, "Failed to register cooling device\n");
....@@ -369,22 +937,51 @@
369937 }
370938 }
371939
940
+ /* Initialize cooling levels per PWM state. */
941
+ for (i = 0; i < MLXSW_THERMAL_MAX_STATE; i++)
942
+ thermal->cooling_levels[i] = max(MLXSW_THERMAL_MIN_STATE, i);
943
+
944
+ thermal->polling_delay = bus_info->low_frequency ?
945
+ MLXSW_THERMAL_SLOW_POLL_INT :
946
+ MLXSW_THERMAL_POLL_INT;
947
+
372948 thermal->tzdev = thermal_zone_device_register("mlxsw",
373949 MLXSW_THERMAL_NUM_TRIPS,
374950 MLXSW_THERMAL_TRIP_MASK,
375951 thermal,
376952 &mlxsw_thermal_ops,
377953 NULL, 0,
378
- MLXSW_THERMAL_POLL_INT);
954
+ thermal->polling_delay);
379955 if (IS_ERR(thermal->tzdev)) {
380956 err = PTR_ERR(thermal->tzdev);
381957 dev_err(dev, "Failed to register thermal zone\n");
382958 goto err_unreg_cdevs;
383959 }
384960
385
- thermal->mode = THERMAL_DEVICE_ENABLED;
961
+ err = mlxsw_thermal_modules_init(dev, core, thermal);
962
+ if (err)
963
+ goto err_unreg_tzdev;
964
+
965
+ err = mlxsw_thermal_gearboxes_init(dev, core, thermal);
966
+ if (err)
967
+ goto err_unreg_modules_tzdev;
968
+
969
+ err = thermal_zone_device_enable(thermal->tzdev);
970
+ if (err)
971
+ goto err_unreg_gearboxes;
972
+
386973 *p_thermal = thermal;
387974 return 0;
975
+
976
+err_unreg_gearboxes:
977
+ mlxsw_thermal_gearboxes_fini(thermal);
978
+err_unreg_modules_tzdev:
979
+ mlxsw_thermal_modules_fini(thermal);
980
+err_unreg_tzdev:
981
+ if (thermal->tzdev) {
982
+ thermal_zone_device_unregister(thermal->tzdev);
983
+ thermal->tzdev = NULL;
984
+ }
388985 err_unreg_cdevs:
389986 for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++)
390987 if (thermal->cdevs[i])
....@@ -398,6 +995,8 @@
398995 {
399996 int i;
400997
998
+ mlxsw_thermal_gearboxes_fini(thermal);
999
+ mlxsw_thermal_modules_fini(thermal);
4011000 if (thermal->tzdev) {
4021001 thermal_zone_device_unregister(thermal->tzdev);
4031002 thermal->tzdev = NULL;