0001
0002
0003
0004
0005
0006 #include <linux/kernel.h>
0007 #include <linux/types.h>
0008 #include <linux/device.h>
0009 #include <linux/sysfs.h>
0010 #include <linux/thermal.h>
0011 #include <linux/err.h>
0012 #include <linux/sfp.h>
0013
0014 #include "core.h"
0015 #include "core_env.h"
0016
0017 #define MLXSW_THERMAL_POLL_INT 1000
0018 #define MLXSW_THERMAL_SLOW_POLL_INT 20000
0019 #define MLXSW_THERMAL_ASIC_TEMP_NORM 75000
0020 #define MLXSW_THERMAL_ASIC_TEMP_HIGH 85000
0021 #define MLXSW_THERMAL_ASIC_TEMP_HOT 105000
0022 #define MLXSW_THERMAL_HYSTERESIS_TEMP 5000
0023 #define MLXSW_THERMAL_MODULE_TEMP_SHIFT (MLXSW_THERMAL_HYSTERESIS_TEMP * 2)
0024 #define MLXSW_THERMAL_TEMP_SCORE_MAX GENMASK(31, 0)
0025 #define MLXSW_THERMAL_MAX_STATE 10
0026 #define MLXSW_THERMAL_MIN_STATE 2
0027 #define MLXSW_THERMAL_MAX_DUTY 255
0028
0029
0030 static char * const mlxsw_thermal_external_allowed_cdev[] = {
0031 "mlxreg_fan",
0032 };
0033
0034 enum mlxsw_thermal_trips {
0035 MLXSW_THERMAL_TEMP_TRIP_NORM,
0036 MLXSW_THERMAL_TEMP_TRIP_HIGH,
0037 MLXSW_THERMAL_TEMP_TRIP_HOT,
0038 };
0039
0040 struct mlxsw_thermal_trip {
0041 int type;
0042 int temp;
0043 int hyst;
0044 int min_state;
0045 int max_state;
0046 };
0047
0048 static const struct mlxsw_thermal_trip default_thermal_trips[] = {
0049 {
0050 .type = THERMAL_TRIP_ACTIVE,
0051 .temp = MLXSW_THERMAL_ASIC_TEMP_NORM,
0052 .hyst = MLXSW_THERMAL_HYSTERESIS_TEMP,
0053 .min_state = 0,
0054 .max_state = (4 * MLXSW_THERMAL_MAX_STATE) / 10,
0055 },
0056 {
0057
0058 .type = THERMAL_TRIP_ACTIVE,
0059 .temp = MLXSW_THERMAL_ASIC_TEMP_HIGH,
0060 .hyst = MLXSW_THERMAL_HYSTERESIS_TEMP,
0061 .min_state = (4 * MLXSW_THERMAL_MAX_STATE) / 10,
0062 .max_state = MLXSW_THERMAL_MAX_STATE,
0063 },
0064 {
0065 .type = THERMAL_TRIP_HOT,
0066 .temp = MLXSW_THERMAL_ASIC_TEMP_HOT,
0067 .min_state = MLXSW_THERMAL_MAX_STATE,
0068 .max_state = MLXSW_THERMAL_MAX_STATE,
0069 },
0070 };
0071
0072 #define MLXSW_THERMAL_NUM_TRIPS ARRAY_SIZE(default_thermal_trips)
0073
0074
0075 #define MLXSW_THERMAL_TRIP_MASK (BIT(MLXSW_THERMAL_NUM_TRIPS) - 1)
0076
0077 struct mlxsw_thermal;
0078
0079 struct mlxsw_thermal_module {
0080 struct mlxsw_thermal *parent;
0081 struct thermal_zone_device *tzdev;
0082 struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
0083 int module;
0084 u8 slot_index;
0085 };
0086
0087 struct mlxsw_thermal_area {
0088 struct mlxsw_thermal_module *tz_module_arr;
0089 u8 tz_module_num;
0090 struct mlxsw_thermal_module *tz_gearbox_arr;
0091 u8 tz_gearbox_num;
0092 u8 slot_index;
0093 bool active;
0094 };
0095
0096 struct mlxsw_thermal {
0097 struct mlxsw_core *core;
0098 const struct mlxsw_bus_info *bus_info;
0099 struct thermal_zone_device *tzdev;
0100 int polling_delay;
0101 struct thermal_cooling_device *cdevs[MLXSW_MFCR_PWMS_MAX];
0102 u8 cooling_levels[MLXSW_THERMAL_MAX_STATE + 1];
0103 struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
0104 unsigned int tz_highest_score;
0105 struct thermal_zone_device *tz_highest_dev;
0106 struct mlxsw_thermal_area line_cards[];
0107 };
0108
0109 static inline u8 mlxsw_state_to_duty(int state)
0110 {
0111 return DIV_ROUND_CLOSEST(state * MLXSW_THERMAL_MAX_DUTY,
0112 MLXSW_THERMAL_MAX_STATE);
0113 }
0114
0115 static inline int mlxsw_duty_to_state(u8 duty)
0116 {
0117 return DIV_ROUND_CLOSEST(duty * MLXSW_THERMAL_MAX_STATE,
0118 MLXSW_THERMAL_MAX_DUTY);
0119 }
0120
0121 static int mlxsw_get_cooling_device_idx(struct mlxsw_thermal *thermal,
0122 struct thermal_cooling_device *cdev)
0123 {
0124 int i;
0125
0126 for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++)
0127 if (thermal->cdevs[i] == cdev)
0128 return i;
0129
0130
0131 for (i = 0; i < ARRAY_SIZE(mlxsw_thermal_external_allowed_cdev); i++) {
0132 if (!strcmp(cdev->type, mlxsw_thermal_external_allowed_cdev[i]))
0133 return 0;
0134 }
0135
0136 return -ENODEV;
0137 }
0138
0139 static void
0140 mlxsw_thermal_module_trips_reset(struct mlxsw_thermal_module *tz)
0141 {
0142 tz->trips[MLXSW_THERMAL_TEMP_TRIP_NORM].temp = 0;
0143 tz->trips[MLXSW_THERMAL_TEMP_TRIP_HIGH].temp = 0;
0144 tz->trips[MLXSW_THERMAL_TEMP_TRIP_HOT].temp = 0;
0145 }
0146
0147 static int
0148 mlxsw_thermal_module_trips_update(struct device *dev, struct mlxsw_core *core,
0149 struct mlxsw_thermal_module *tz,
0150 int crit_temp, int emerg_temp)
0151 {
0152 int err;
0153
0154
0155
0156
0157 if (!emerg_temp || !crit_temp) {
0158 err = mlxsw_env_module_temp_thresholds_get(core, tz->slot_index,
0159 tz->module,
0160 SFP_TEMP_HIGH_WARN,
0161 &crit_temp);
0162 if (err)
0163 return err;
0164
0165 err = mlxsw_env_module_temp_thresholds_get(core, tz->slot_index,
0166 tz->module,
0167 SFP_TEMP_HIGH_ALARM,
0168 &emerg_temp);
0169 if (err)
0170 return err;
0171 }
0172
0173 if (crit_temp > emerg_temp) {
0174 dev_warn(dev, "%s : Critical threshold %d is above emergency threshold %d\n",
0175 tz->tzdev->type, crit_temp, emerg_temp);
0176 return 0;
0177 }
0178
0179
0180
0181
0182
0183
0184
0185 if (crit_temp >= MLXSW_THERMAL_MODULE_TEMP_SHIFT)
0186 tz->trips[MLXSW_THERMAL_TEMP_TRIP_NORM].temp = crit_temp -
0187 MLXSW_THERMAL_MODULE_TEMP_SHIFT;
0188 else
0189 tz->trips[MLXSW_THERMAL_TEMP_TRIP_NORM].temp = crit_temp;
0190 tz->trips[MLXSW_THERMAL_TEMP_TRIP_HIGH].temp = crit_temp;
0191 tz->trips[MLXSW_THERMAL_TEMP_TRIP_HOT].temp = emerg_temp;
0192
0193 return 0;
0194 }
0195
0196 static void mlxsw_thermal_tz_score_update(struct mlxsw_thermal *thermal,
0197 struct thermal_zone_device *tzdev,
0198 struct mlxsw_thermal_trip *trips,
0199 int temp)
0200 {
0201 struct mlxsw_thermal_trip *trip = trips;
0202 unsigned int score, delta, i, shift = 1;
0203
0204
0205
0206
0207 score = MLXSW_THERMAL_TEMP_SCORE_MAX;
0208 for (i = MLXSW_THERMAL_TEMP_TRIP_NORM; i < MLXSW_THERMAL_NUM_TRIPS;
0209 i++, trip++) {
0210 if (temp < trip->temp) {
0211 delta = DIV_ROUND_CLOSEST(temp, trip->temp - temp);
0212 score = delta * shift;
0213 break;
0214 }
0215 shift *= 256;
0216 }
0217
0218 if (score > thermal->tz_highest_score) {
0219 thermal->tz_highest_score = score;
0220 thermal->tz_highest_dev = tzdev;
0221 }
0222 }
0223
0224 static int mlxsw_thermal_bind(struct thermal_zone_device *tzdev,
0225 struct thermal_cooling_device *cdev)
0226 {
0227 struct mlxsw_thermal *thermal = tzdev->devdata;
0228 struct device *dev = thermal->bus_info->dev;
0229 int i, err;
0230
0231
0232 if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0)
0233 return 0;
0234
0235 for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) {
0236 const struct mlxsw_thermal_trip *trip = &thermal->trips[i];
0237
0238 err = thermal_zone_bind_cooling_device(tzdev, i, cdev,
0239 trip->max_state,
0240 trip->min_state,
0241 THERMAL_WEIGHT_DEFAULT);
0242 if (err < 0) {
0243 dev_err(dev, "Failed to bind cooling device to trip %d\n", i);
0244 return err;
0245 }
0246 }
0247 return 0;
0248 }
0249
0250 static int mlxsw_thermal_unbind(struct thermal_zone_device *tzdev,
0251 struct thermal_cooling_device *cdev)
0252 {
0253 struct mlxsw_thermal *thermal = tzdev->devdata;
0254 struct device *dev = thermal->bus_info->dev;
0255 int i;
0256 int err;
0257
0258
0259 if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0)
0260 return 0;
0261
0262 for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) {
0263 err = thermal_zone_unbind_cooling_device(tzdev, i, cdev);
0264 if (err < 0) {
0265 dev_err(dev, "Failed to unbind cooling device\n");
0266 return err;
0267 }
0268 }
0269 return 0;
0270 }
0271
0272 static int mlxsw_thermal_get_temp(struct thermal_zone_device *tzdev,
0273 int *p_temp)
0274 {
0275 struct mlxsw_thermal *thermal = tzdev->devdata;
0276 struct device *dev = thermal->bus_info->dev;
0277 char mtmp_pl[MLXSW_REG_MTMP_LEN];
0278 int temp;
0279 int err;
0280
0281 mlxsw_reg_mtmp_pack(mtmp_pl, 0, 0, false, false);
0282
0283 err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl);
0284 if (err) {
0285 dev_err(dev, "Failed to query temp sensor\n");
0286 return err;
0287 }
0288 mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL, NULL, NULL);
0289 if (temp > 0)
0290 mlxsw_thermal_tz_score_update(thermal, tzdev, thermal->trips,
0291 temp);
0292
0293 *p_temp = temp;
0294 return 0;
0295 }
0296
0297 static int mlxsw_thermal_get_trip_type(struct thermal_zone_device *tzdev,
0298 int trip,
0299 enum thermal_trip_type *p_type)
0300 {
0301 struct mlxsw_thermal *thermal = tzdev->devdata;
0302
0303 if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
0304 return -EINVAL;
0305
0306 *p_type = thermal->trips[trip].type;
0307 return 0;
0308 }
0309
0310 static int mlxsw_thermal_get_trip_temp(struct thermal_zone_device *tzdev,
0311 int trip, int *p_temp)
0312 {
0313 struct mlxsw_thermal *thermal = tzdev->devdata;
0314
0315 if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
0316 return -EINVAL;
0317
0318 *p_temp = thermal->trips[trip].temp;
0319 return 0;
0320 }
0321
0322 static int mlxsw_thermal_set_trip_temp(struct thermal_zone_device *tzdev,
0323 int trip, int temp)
0324 {
0325 struct mlxsw_thermal *thermal = tzdev->devdata;
0326
0327 if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
0328 return -EINVAL;
0329
0330 thermal->trips[trip].temp = temp;
0331 return 0;
0332 }
0333
0334 static int mlxsw_thermal_get_trip_hyst(struct thermal_zone_device *tzdev,
0335 int trip, int *p_hyst)
0336 {
0337 struct mlxsw_thermal *thermal = tzdev->devdata;
0338
0339 *p_hyst = thermal->trips[trip].hyst;
0340 return 0;
0341 }
0342
0343 static int mlxsw_thermal_set_trip_hyst(struct thermal_zone_device *tzdev,
0344 int trip, int hyst)
0345 {
0346 struct mlxsw_thermal *thermal = tzdev->devdata;
0347
0348 thermal->trips[trip].hyst = hyst;
0349 return 0;
0350 }
0351
0352 static int mlxsw_thermal_trend_get(struct thermal_zone_device *tzdev,
0353 int trip, enum thermal_trend *trend)
0354 {
0355 struct mlxsw_thermal *thermal = tzdev->devdata;
0356
0357 if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
0358 return -EINVAL;
0359
0360 if (tzdev == thermal->tz_highest_dev)
0361 return 1;
0362
0363 *trend = THERMAL_TREND_STABLE;
0364 return 0;
0365 }
0366
0367 static struct thermal_zone_params mlxsw_thermal_params = {
0368 .no_hwmon = true,
0369 };
0370
0371 static struct thermal_zone_device_ops mlxsw_thermal_ops = {
0372 .bind = mlxsw_thermal_bind,
0373 .unbind = mlxsw_thermal_unbind,
0374 .get_temp = mlxsw_thermal_get_temp,
0375 .get_trip_type = mlxsw_thermal_get_trip_type,
0376 .get_trip_temp = mlxsw_thermal_get_trip_temp,
0377 .set_trip_temp = mlxsw_thermal_set_trip_temp,
0378 .get_trip_hyst = mlxsw_thermal_get_trip_hyst,
0379 .set_trip_hyst = mlxsw_thermal_set_trip_hyst,
0380 .get_trend = mlxsw_thermal_trend_get,
0381 };
0382
0383 static int mlxsw_thermal_module_bind(struct thermal_zone_device *tzdev,
0384 struct thermal_cooling_device *cdev)
0385 {
0386 struct mlxsw_thermal_module *tz = tzdev->devdata;
0387 struct mlxsw_thermal *thermal = tz->parent;
0388 int i, j, err;
0389
0390
0391 if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0)
0392 return 0;
0393
0394 for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) {
0395 const struct mlxsw_thermal_trip *trip = &tz->trips[i];
0396
0397 err = thermal_zone_bind_cooling_device(tzdev, i, cdev,
0398 trip->max_state,
0399 trip->min_state,
0400 THERMAL_WEIGHT_DEFAULT);
0401 if (err < 0)
0402 goto err_thermal_zone_bind_cooling_device;
0403 }
0404 return 0;
0405
0406 err_thermal_zone_bind_cooling_device:
0407 for (j = i - 1; j >= 0; j--)
0408 thermal_zone_unbind_cooling_device(tzdev, j, cdev);
0409 return err;
0410 }
0411
0412 static int mlxsw_thermal_module_unbind(struct thermal_zone_device *tzdev,
0413 struct thermal_cooling_device *cdev)
0414 {
0415 struct mlxsw_thermal_module *tz = tzdev->devdata;
0416 struct mlxsw_thermal *thermal = tz->parent;
0417 int i;
0418 int err;
0419
0420
0421 if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0)
0422 return 0;
0423
0424 for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) {
0425 err = thermal_zone_unbind_cooling_device(tzdev, i, cdev);
0426 WARN_ON(err);
0427 }
0428 return err;
0429 }
0430
0431 static void
0432 mlxsw_thermal_module_temp_and_thresholds_get(struct mlxsw_core *core,
0433 u8 slot_index, u16 sensor_index,
0434 int *p_temp, int *p_crit_temp,
0435 int *p_emerg_temp)
0436 {
0437 char mtmp_pl[MLXSW_REG_MTMP_LEN];
0438 int err;
0439
0440
0441 mlxsw_reg_mtmp_pack(mtmp_pl, slot_index, sensor_index,
0442 false, false);
0443 err = mlxsw_reg_query(core, MLXSW_REG(mtmp), mtmp_pl);
0444 if (err) {
0445
0446
0447
0448 *p_temp = 0;
0449 *p_crit_temp = 0;
0450 *p_emerg_temp = 0;
0451
0452 return;
0453 }
0454 mlxsw_reg_mtmp_unpack(mtmp_pl, p_temp, NULL, p_crit_temp, p_emerg_temp,
0455 NULL);
0456 }
0457
0458 static int mlxsw_thermal_module_temp_get(struct thermal_zone_device *tzdev,
0459 int *p_temp)
0460 {
0461 struct mlxsw_thermal_module *tz = tzdev->devdata;
0462 struct mlxsw_thermal *thermal = tz->parent;
0463 int temp, crit_temp, emerg_temp;
0464 struct device *dev;
0465 u16 sensor_index;
0466 int err;
0467
0468 dev = thermal->bus_info->dev;
0469 sensor_index = MLXSW_REG_MTMP_MODULE_INDEX_MIN + tz->module;
0470
0471
0472 mlxsw_thermal_module_temp_and_thresholds_get(thermal->core,
0473 tz->slot_index,
0474 sensor_index, &temp,
0475 &crit_temp, &emerg_temp);
0476 *p_temp = temp;
0477
0478 if (!temp)
0479 return 0;
0480
0481
0482 err = mlxsw_thermal_module_trips_update(dev, thermal->core, tz,
0483 crit_temp, emerg_temp);
0484 if (!err && temp > 0)
0485 mlxsw_thermal_tz_score_update(thermal, tzdev, tz->trips, temp);
0486
0487 return 0;
0488 }
0489
0490 static int
0491 mlxsw_thermal_module_trip_type_get(struct thermal_zone_device *tzdev, int trip,
0492 enum thermal_trip_type *p_type)
0493 {
0494 struct mlxsw_thermal_module *tz = tzdev->devdata;
0495
0496 if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
0497 return -EINVAL;
0498
0499 *p_type = tz->trips[trip].type;
0500 return 0;
0501 }
0502
0503 static int
0504 mlxsw_thermal_module_trip_temp_get(struct thermal_zone_device *tzdev,
0505 int trip, int *p_temp)
0506 {
0507 struct mlxsw_thermal_module *tz = tzdev->devdata;
0508
0509 if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
0510 return -EINVAL;
0511
0512 *p_temp = tz->trips[trip].temp;
0513 return 0;
0514 }
0515
0516 static int
0517 mlxsw_thermal_module_trip_temp_set(struct thermal_zone_device *tzdev,
0518 int trip, int temp)
0519 {
0520 struct mlxsw_thermal_module *tz = tzdev->devdata;
0521
0522 if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
0523 return -EINVAL;
0524
0525 tz->trips[trip].temp = temp;
0526 return 0;
0527 }
0528
0529 static int
0530 mlxsw_thermal_module_trip_hyst_get(struct thermal_zone_device *tzdev, int trip,
0531 int *p_hyst)
0532 {
0533 struct mlxsw_thermal_module *tz = tzdev->devdata;
0534
0535 *p_hyst = tz->trips[trip].hyst;
0536 return 0;
0537 }
0538
0539 static int
0540 mlxsw_thermal_module_trip_hyst_set(struct thermal_zone_device *tzdev, int trip,
0541 int hyst)
0542 {
0543 struct mlxsw_thermal_module *tz = tzdev->devdata;
0544
0545 tz->trips[trip].hyst = hyst;
0546 return 0;
0547 }
0548
0549 static int mlxsw_thermal_module_trend_get(struct thermal_zone_device *tzdev,
0550 int trip, enum thermal_trend *trend)
0551 {
0552 struct mlxsw_thermal_module *tz = tzdev->devdata;
0553 struct mlxsw_thermal *thermal = tz->parent;
0554
0555 if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
0556 return -EINVAL;
0557
0558 if (tzdev == thermal->tz_highest_dev)
0559 return 1;
0560
0561 *trend = THERMAL_TREND_STABLE;
0562 return 0;
0563 }
0564
0565 static struct thermal_zone_device_ops mlxsw_thermal_module_ops = {
0566 .bind = mlxsw_thermal_module_bind,
0567 .unbind = mlxsw_thermal_module_unbind,
0568 .get_temp = mlxsw_thermal_module_temp_get,
0569 .get_trip_type = mlxsw_thermal_module_trip_type_get,
0570 .get_trip_temp = mlxsw_thermal_module_trip_temp_get,
0571 .set_trip_temp = mlxsw_thermal_module_trip_temp_set,
0572 .get_trip_hyst = mlxsw_thermal_module_trip_hyst_get,
0573 .set_trip_hyst = mlxsw_thermal_module_trip_hyst_set,
0574 .get_trend = mlxsw_thermal_module_trend_get,
0575 };
0576
0577 static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev,
0578 int *p_temp)
0579 {
0580 struct mlxsw_thermal_module *tz = tzdev->devdata;
0581 struct mlxsw_thermal *thermal = tz->parent;
0582 char mtmp_pl[MLXSW_REG_MTMP_LEN];
0583 u16 index;
0584 int temp;
0585 int err;
0586
0587 index = MLXSW_REG_MTMP_GBOX_INDEX_MIN + tz->module;
0588 mlxsw_reg_mtmp_pack(mtmp_pl, tz->slot_index, index, false, false);
0589
0590 err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl);
0591 if (err)
0592 return err;
0593
0594 mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL, NULL, NULL);
0595 if (temp > 0)
0596 mlxsw_thermal_tz_score_update(thermal, tzdev, tz->trips, temp);
0597
0598 *p_temp = temp;
0599 return 0;
0600 }
0601
0602 static struct thermal_zone_device_ops mlxsw_thermal_gearbox_ops = {
0603 .bind = mlxsw_thermal_module_bind,
0604 .unbind = mlxsw_thermal_module_unbind,
0605 .get_temp = mlxsw_thermal_gearbox_temp_get,
0606 .get_trip_type = mlxsw_thermal_module_trip_type_get,
0607 .get_trip_temp = mlxsw_thermal_module_trip_temp_get,
0608 .set_trip_temp = mlxsw_thermal_module_trip_temp_set,
0609 .get_trip_hyst = mlxsw_thermal_module_trip_hyst_get,
0610 .set_trip_hyst = mlxsw_thermal_module_trip_hyst_set,
0611 .get_trend = mlxsw_thermal_module_trend_get,
0612 };
0613
0614 static int mlxsw_thermal_get_max_state(struct thermal_cooling_device *cdev,
0615 unsigned long *p_state)
0616 {
0617 *p_state = MLXSW_THERMAL_MAX_STATE;
0618 return 0;
0619 }
0620
0621 static int mlxsw_thermal_get_cur_state(struct thermal_cooling_device *cdev,
0622 unsigned long *p_state)
0623
0624 {
0625 struct mlxsw_thermal *thermal = cdev->devdata;
0626 struct device *dev = thermal->bus_info->dev;
0627 char mfsc_pl[MLXSW_REG_MFSC_LEN];
0628 int err, idx;
0629 u8 duty;
0630
0631 idx = mlxsw_get_cooling_device_idx(thermal, cdev);
0632 if (idx < 0)
0633 return idx;
0634
0635 mlxsw_reg_mfsc_pack(mfsc_pl, idx, 0);
0636 err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfsc), mfsc_pl);
0637 if (err) {
0638 dev_err(dev, "Failed to query PWM duty\n");
0639 return err;
0640 }
0641
0642 duty = mlxsw_reg_mfsc_pwm_duty_cycle_get(mfsc_pl);
0643 *p_state = mlxsw_duty_to_state(duty);
0644 return 0;
0645 }
0646
0647 static int mlxsw_thermal_set_cur_state(struct thermal_cooling_device *cdev,
0648 unsigned long state)
0649
0650 {
0651 struct mlxsw_thermal *thermal = cdev->devdata;
0652 struct device *dev = thermal->bus_info->dev;
0653 char mfsc_pl[MLXSW_REG_MFSC_LEN];
0654 int idx;
0655 int err;
0656
0657 if (state > MLXSW_THERMAL_MAX_STATE)
0658 return -EINVAL;
0659
0660 idx = mlxsw_get_cooling_device_idx(thermal, cdev);
0661 if (idx < 0)
0662 return idx;
0663
0664
0665 state = thermal->cooling_levels[state];
0666 mlxsw_reg_mfsc_pack(mfsc_pl, idx, mlxsw_state_to_duty(state));
0667 err = mlxsw_reg_write(thermal->core, MLXSW_REG(mfsc), mfsc_pl);
0668 if (err) {
0669 dev_err(dev, "Failed to write PWM duty\n");
0670 return err;
0671 }
0672 return 0;
0673 }
0674
0675 static const struct thermal_cooling_device_ops mlxsw_cooling_ops = {
0676 .get_max_state = mlxsw_thermal_get_max_state,
0677 .get_cur_state = mlxsw_thermal_get_cur_state,
0678 .set_cur_state = mlxsw_thermal_set_cur_state,
0679 };
0680
0681 static int
0682 mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz)
0683 {
0684 char tz_name[THERMAL_NAME_LENGTH];
0685 int err;
0686
0687 if (module_tz->slot_index)
0688 snprintf(tz_name, sizeof(tz_name), "mlxsw-lc%d-module%d",
0689 module_tz->slot_index, module_tz->module + 1);
0690 else
0691 snprintf(tz_name, sizeof(tz_name), "mlxsw-module%d",
0692 module_tz->module + 1);
0693 module_tz->tzdev = thermal_zone_device_register(tz_name,
0694 MLXSW_THERMAL_NUM_TRIPS,
0695 MLXSW_THERMAL_TRIP_MASK,
0696 module_tz,
0697 &mlxsw_thermal_module_ops,
0698 &mlxsw_thermal_params,
0699 0,
0700 module_tz->parent->polling_delay);
0701 if (IS_ERR(module_tz->tzdev)) {
0702 err = PTR_ERR(module_tz->tzdev);
0703 return err;
0704 }
0705
0706 err = thermal_zone_device_enable(module_tz->tzdev);
0707 if (err)
0708 thermal_zone_device_unregister(module_tz->tzdev);
0709
0710 return err;
0711 }
0712
0713 static void mlxsw_thermal_module_tz_fini(struct thermal_zone_device *tzdev)
0714 {
0715 thermal_zone_device_unregister(tzdev);
0716 }
0717
0718 static int
0719 mlxsw_thermal_module_init(struct device *dev, struct mlxsw_core *core,
0720 struct mlxsw_thermal *thermal,
0721 struct mlxsw_thermal_area *area, u8 module)
0722 {
0723 struct mlxsw_thermal_module *module_tz;
0724 int dummy_temp, crit_temp, emerg_temp;
0725 u16 sensor_index;
0726
0727 sensor_index = MLXSW_REG_MTMP_MODULE_INDEX_MIN + module;
0728 module_tz = &area->tz_module_arr[module];
0729
0730 if (module_tz->parent)
0731 return 0;
0732 module_tz->module = module;
0733 module_tz->slot_index = area->slot_index;
0734 module_tz->parent = thermal;
0735 memcpy(module_tz->trips, default_thermal_trips,
0736 sizeof(thermal->trips));
0737
0738 mlxsw_thermal_module_trips_reset(module_tz);
0739
0740 mlxsw_thermal_module_temp_and_thresholds_get(core, area->slot_index,
0741 sensor_index, &dummy_temp,
0742 &crit_temp, &emerg_temp);
0743
0744 return mlxsw_thermal_module_trips_update(dev, core, module_tz,
0745 crit_temp, emerg_temp);
0746 }
0747
0748 static void mlxsw_thermal_module_fini(struct mlxsw_thermal_module *module_tz)
0749 {
0750 if (module_tz && module_tz->tzdev) {
0751 mlxsw_thermal_module_tz_fini(module_tz->tzdev);
0752 module_tz->tzdev = NULL;
0753 module_tz->parent = NULL;
0754 }
0755 }
0756
0757 static int
0758 mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core,
0759 struct mlxsw_thermal *thermal,
0760 struct mlxsw_thermal_area *area)
0761 {
0762 struct mlxsw_thermal_module *module_tz;
0763 char mgpir_pl[MLXSW_REG_MGPIR_LEN];
0764 int i, err;
0765
0766 mlxsw_reg_mgpir_pack(mgpir_pl, area->slot_index);
0767 err = mlxsw_reg_query(core, MLXSW_REG(mgpir), mgpir_pl);
0768 if (err)
0769 return err;
0770
0771 mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL,
0772 &area->tz_module_num, NULL);
0773
0774
0775 if (!area->tz_module_num)
0776 return 0;
0777
0778 area->tz_module_arr = kcalloc(area->tz_module_num,
0779 sizeof(*area->tz_module_arr),
0780 GFP_KERNEL);
0781 if (!area->tz_module_arr)
0782 return -ENOMEM;
0783
0784 for (i = 0; i < area->tz_module_num; i++) {
0785 err = mlxsw_thermal_module_init(dev, core, thermal, area, i);
0786 if (err)
0787 goto err_thermal_module_init;
0788 }
0789
0790 for (i = 0; i < area->tz_module_num; i++) {
0791 module_tz = &area->tz_module_arr[i];
0792 if (!module_tz->parent)
0793 continue;
0794 err = mlxsw_thermal_module_tz_init(module_tz);
0795 if (err)
0796 goto err_thermal_module_tz_init;
0797 }
0798
0799 return 0;
0800
0801 err_thermal_module_tz_init:
0802 err_thermal_module_init:
0803 for (i = area->tz_module_num - 1; i >= 0; i--)
0804 mlxsw_thermal_module_fini(&area->tz_module_arr[i]);
0805 kfree(area->tz_module_arr);
0806 return err;
0807 }
0808
0809 static void
0810 mlxsw_thermal_modules_fini(struct mlxsw_thermal *thermal,
0811 struct mlxsw_thermal_area *area)
0812 {
0813 int i;
0814
0815 for (i = area->tz_module_num - 1; i >= 0; i--)
0816 mlxsw_thermal_module_fini(&area->tz_module_arr[i]);
0817 kfree(area->tz_module_arr);
0818 }
0819
0820 static int
0821 mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz)
0822 {
0823 char tz_name[THERMAL_NAME_LENGTH];
0824 int ret;
0825
0826 if (gearbox_tz->slot_index)
0827 snprintf(tz_name, sizeof(tz_name), "mlxsw-lc%d-gearbox%d",
0828 gearbox_tz->slot_index, gearbox_tz->module + 1);
0829 else
0830 snprintf(tz_name, sizeof(tz_name), "mlxsw-gearbox%d",
0831 gearbox_tz->module + 1);
0832 gearbox_tz->tzdev = thermal_zone_device_register(tz_name,
0833 MLXSW_THERMAL_NUM_TRIPS,
0834 MLXSW_THERMAL_TRIP_MASK,
0835 gearbox_tz,
0836 &mlxsw_thermal_gearbox_ops,
0837 &mlxsw_thermal_params, 0,
0838 gearbox_tz->parent->polling_delay);
0839 if (IS_ERR(gearbox_tz->tzdev))
0840 return PTR_ERR(gearbox_tz->tzdev);
0841
0842 ret = thermal_zone_device_enable(gearbox_tz->tzdev);
0843 if (ret)
0844 thermal_zone_device_unregister(gearbox_tz->tzdev);
0845
0846 return ret;
0847 }
0848
0849 static void
0850 mlxsw_thermal_gearbox_tz_fini(struct mlxsw_thermal_module *gearbox_tz)
0851 {
0852 thermal_zone_device_unregister(gearbox_tz->tzdev);
0853 }
0854
0855 static int
0856 mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core,
0857 struct mlxsw_thermal *thermal,
0858 struct mlxsw_thermal_area *area)
0859 {
0860 enum mlxsw_reg_mgpir_device_type device_type;
0861 struct mlxsw_thermal_module *gearbox_tz;
0862 char mgpir_pl[MLXSW_REG_MGPIR_LEN];
0863 u8 gbox_num;
0864 int i;
0865 int err;
0866
0867 mlxsw_reg_mgpir_pack(mgpir_pl, area->slot_index);
0868 err = mlxsw_reg_query(core, MLXSW_REG(mgpir), mgpir_pl);
0869 if (err)
0870 return err;
0871
0872 mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, &device_type, NULL,
0873 NULL, NULL);
0874 if (device_type != MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE ||
0875 !gbox_num)
0876 return 0;
0877
0878 area->tz_gearbox_num = gbox_num;
0879 area->tz_gearbox_arr = kcalloc(area->tz_gearbox_num,
0880 sizeof(*area->tz_gearbox_arr),
0881 GFP_KERNEL);
0882 if (!area->tz_gearbox_arr)
0883 return -ENOMEM;
0884
0885 for (i = 0; i < area->tz_gearbox_num; i++) {
0886 gearbox_tz = &area->tz_gearbox_arr[i];
0887 memcpy(gearbox_tz->trips, default_thermal_trips,
0888 sizeof(thermal->trips));
0889 gearbox_tz->module = i;
0890 gearbox_tz->parent = thermal;
0891 gearbox_tz->slot_index = area->slot_index;
0892 err = mlxsw_thermal_gearbox_tz_init(gearbox_tz);
0893 if (err)
0894 goto err_thermal_gearbox_tz_init;
0895 }
0896
0897 return 0;
0898
0899 err_thermal_gearbox_tz_init:
0900 for (i--; i >= 0; i--)
0901 mlxsw_thermal_gearbox_tz_fini(&area->tz_gearbox_arr[i]);
0902 kfree(area->tz_gearbox_arr);
0903 return err;
0904 }
0905
0906 static void
0907 mlxsw_thermal_gearboxes_fini(struct mlxsw_thermal *thermal,
0908 struct mlxsw_thermal_area *area)
0909 {
0910 int i;
0911
0912 for (i = area->tz_gearbox_num - 1; i >= 0; i--)
0913 mlxsw_thermal_gearbox_tz_fini(&area->tz_gearbox_arr[i]);
0914 kfree(area->tz_gearbox_arr);
0915 }
0916
0917 static void
0918 mlxsw_thermal_got_active(struct mlxsw_core *mlxsw_core, u8 slot_index,
0919 void *priv)
0920 {
0921 struct mlxsw_thermal *thermal = priv;
0922 struct mlxsw_thermal_area *linecard;
0923 int err;
0924
0925 linecard = &thermal->line_cards[slot_index];
0926
0927 if (linecard->active)
0928 return;
0929
0930 linecard->slot_index = slot_index;
0931 err = mlxsw_thermal_modules_init(thermal->bus_info->dev, thermal->core,
0932 thermal, linecard);
0933 if (err) {
0934 dev_err(thermal->bus_info->dev, "Failed to configure thermal objects for line card modules in slot %d\n",
0935 slot_index);
0936 return;
0937 }
0938
0939 err = mlxsw_thermal_gearboxes_init(thermal->bus_info->dev,
0940 thermal->core, thermal, linecard);
0941 if (err) {
0942 dev_err(thermal->bus_info->dev, "Failed to configure thermal objects for line card gearboxes in slot %d\n",
0943 slot_index);
0944 goto err_thermal_linecard_gearboxes_init;
0945 }
0946
0947 linecard->active = true;
0948
0949 return;
0950
0951 err_thermal_linecard_gearboxes_init:
0952 mlxsw_thermal_modules_fini(thermal, linecard);
0953 }
0954
0955 static void
0956 mlxsw_thermal_got_inactive(struct mlxsw_core *mlxsw_core, u8 slot_index,
0957 void *priv)
0958 {
0959 struct mlxsw_thermal *thermal = priv;
0960 struct mlxsw_thermal_area *linecard;
0961
0962 linecard = &thermal->line_cards[slot_index];
0963 if (!linecard->active)
0964 return;
0965 linecard->active = false;
0966 mlxsw_thermal_gearboxes_fini(thermal, linecard);
0967 mlxsw_thermal_modules_fini(thermal, linecard);
0968 }
0969
0970 static struct mlxsw_linecards_event_ops mlxsw_thermal_event_ops = {
0971 .got_active = mlxsw_thermal_got_active,
0972 .got_inactive = mlxsw_thermal_got_inactive,
0973 };
0974
0975 int mlxsw_thermal_init(struct mlxsw_core *core,
0976 const struct mlxsw_bus_info *bus_info,
0977 struct mlxsw_thermal **p_thermal)
0978 {
0979 char mfcr_pl[MLXSW_REG_MFCR_LEN] = { 0 };
0980 enum mlxsw_reg_mfcr_pwm_frequency freq;
0981 struct device *dev = bus_info->dev;
0982 char mgpir_pl[MLXSW_REG_MGPIR_LEN];
0983 struct mlxsw_thermal *thermal;
0984 u8 pwm_active, num_of_slots;
0985 u16 tacho_active;
0986 int err, i;
0987
0988 mlxsw_reg_mgpir_pack(mgpir_pl, 0);
0989 err = mlxsw_reg_query(core, MLXSW_REG(mgpir), mgpir_pl);
0990 if (err)
0991 return err;
0992
0993 mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, NULL,
0994 &num_of_slots);
0995
0996 thermal = kzalloc(struct_size(thermal, line_cards, num_of_slots + 1),
0997 GFP_KERNEL);
0998 if (!thermal)
0999 return -ENOMEM;
1000
1001 thermal->core = core;
1002 thermal->bus_info = bus_info;
1003 memcpy(thermal->trips, default_thermal_trips, sizeof(thermal->trips));
1004 thermal->line_cards[0].slot_index = 0;
1005
1006 err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfcr), mfcr_pl);
1007 if (err) {
1008 dev_err(dev, "Failed to probe PWMs\n");
1009 goto err_reg_query;
1010 }
1011 mlxsw_reg_mfcr_unpack(mfcr_pl, &freq, &tacho_active, &pwm_active);
1012
1013 for (i = 0; i < MLXSW_MFCR_TACHOS_MAX; i++) {
1014 if (tacho_active & BIT(i)) {
1015 char mfsl_pl[MLXSW_REG_MFSL_LEN];
1016
1017 mlxsw_reg_mfsl_pack(mfsl_pl, i, 0, 0);
1018
1019
1020 err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfsl),
1021 mfsl_pl);
1022 if (err)
1023 goto err_reg_query;
1024
1025
1026 mlxsw_reg_mfsl_tach_min_set(mfsl_pl, 0);
1027 err = mlxsw_reg_write(thermal->core, MLXSW_REG(mfsl),
1028 mfsl_pl);
1029 if (err)
1030 goto err_reg_write;
1031 }
1032 }
1033 for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++) {
1034 if (pwm_active & BIT(i)) {
1035 struct thermal_cooling_device *cdev;
1036
1037 cdev = thermal_cooling_device_register("mlxsw_fan",
1038 thermal,
1039 &mlxsw_cooling_ops);
1040 if (IS_ERR(cdev)) {
1041 err = PTR_ERR(cdev);
1042 dev_err(dev, "Failed to register cooling device\n");
1043 goto err_thermal_cooling_device_register;
1044 }
1045 thermal->cdevs[i] = cdev;
1046 }
1047 }
1048
1049
1050 for (i = 0; i < MLXSW_THERMAL_MAX_STATE; i++)
1051 thermal->cooling_levels[i] = max(MLXSW_THERMAL_MIN_STATE, i);
1052
1053 thermal->polling_delay = bus_info->low_frequency ?
1054 MLXSW_THERMAL_SLOW_POLL_INT :
1055 MLXSW_THERMAL_POLL_INT;
1056
1057 thermal->tzdev = thermal_zone_device_register("mlxsw",
1058 MLXSW_THERMAL_NUM_TRIPS,
1059 MLXSW_THERMAL_TRIP_MASK,
1060 thermal,
1061 &mlxsw_thermal_ops,
1062 &mlxsw_thermal_params, 0,
1063 thermal->polling_delay);
1064 if (IS_ERR(thermal->tzdev)) {
1065 err = PTR_ERR(thermal->tzdev);
1066 dev_err(dev, "Failed to register thermal zone\n");
1067 goto err_thermal_zone_device_register;
1068 }
1069
1070 err = mlxsw_thermal_modules_init(dev, core, thermal,
1071 &thermal->line_cards[0]);
1072 if (err)
1073 goto err_thermal_modules_init;
1074
1075 err = mlxsw_thermal_gearboxes_init(dev, core, thermal,
1076 &thermal->line_cards[0]);
1077 if (err)
1078 goto err_thermal_gearboxes_init;
1079
1080 err = mlxsw_linecards_event_ops_register(core,
1081 &mlxsw_thermal_event_ops,
1082 thermal);
1083 if (err)
1084 goto err_linecards_event_ops_register;
1085
1086 err = thermal_zone_device_enable(thermal->tzdev);
1087 if (err)
1088 goto err_thermal_zone_device_enable;
1089
1090 thermal->line_cards[0].active = true;
1091 *p_thermal = thermal;
1092 return 0;
1093
1094 err_thermal_zone_device_enable:
1095 mlxsw_linecards_event_ops_unregister(thermal->core,
1096 &mlxsw_thermal_event_ops,
1097 thermal);
1098 err_linecards_event_ops_register:
1099 mlxsw_thermal_gearboxes_fini(thermal, &thermal->line_cards[0]);
1100 err_thermal_gearboxes_init:
1101 mlxsw_thermal_modules_fini(thermal, &thermal->line_cards[0]);
1102 err_thermal_modules_init:
1103 if (thermal->tzdev) {
1104 thermal_zone_device_unregister(thermal->tzdev);
1105 thermal->tzdev = NULL;
1106 }
1107 err_thermal_zone_device_register:
1108 err_thermal_cooling_device_register:
1109 for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++)
1110 if (thermal->cdevs[i])
1111 thermal_cooling_device_unregister(thermal->cdevs[i]);
1112 err_reg_write:
1113 err_reg_query:
1114 kfree(thermal);
1115 return err;
1116 }
1117
1118 void mlxsw_thermal_fini(struct mlxsw_thermal *thermal)
1119 {
1120 int i;
1121
1122 thermal->line_cards[0].active = false;
1123 mlxsw_linecards_event_ops_unregister(thermal->core,
1124 &mlxsw_thermal_event_ops,
1125 thermal);
1126 mlxsw_thermal_gearboxes_fini(thermal, &thermal->line_cards[0]);
1127 mlxsw_thermal_modules_fini(thermal, &thermal->line_cards[0]);
1128 if (thermal->tzdev) {
1129 thermal_zone_device_unregister(thermal->tzdev);
1130 thermal->tzdev = NULL;
1131 }
1132
1133 for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++) {
1134 if (thermal->cdevs[i]) {
1135 thermal_cooling_device_unregister(thermal->cdevs[i]);
1136 thermal->cdevs[i] = NULL;
1137 }
1138 }
1139
1140 kfree(thermal);
1141 }