core_thermal.c (31002B)
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_HYSTERESIS_TEMP 5000 /* 5C */ 23#define MLXSW_THERMAL_MODULE_TEMP_SHIFT (MLXSW_THERMAL_HYSTERESIS_TEMP * 2) 24#define MLXSW_THERMAL_TEMP_SCORE_MAX GENMASK(31, 0) 25#define MLXSW_THERMAL_MAX_STATE 10 26#define MLXSW_THERMAL_MIN_STATE 2 27#define MLXSW_THERMAL_MAX_DUTY 255 28 29/* External cooling devices, allowed for binding to mlxsw thermal zones. */ 30static char * const mlxsw_thermal_external_allowed_cdev[] = { 31 "mlxreg_fan", 32}; 33 34enum mlxsw_thermal_trips { 35 MLXSW_THERMAL_TEMP_TRIP_NORM, 36 MLXSW_THERMAL_TEMP_TRIP_HIGH, 37 MLXSW_THERMAL_TEMP_TRIP_HOT, 38}; 39 40struct mlxsw_thermal_trip { 41 int type; 42 int temp; 43 int hyst; 44 int min_state; 45 int max_state; 46}; 47 48static const struct mlxsw_thermal_trip default_thermal_trips[] = { 49 { /* In range - 0-40% PWM */ 50 .type = THERMAL_TRIP_ACTIVE, 51 .temp = MLXSW_THERMAL_ASIC_TEMP_NORM, 52 .hyst = MLXSW_THERMAL_HYSTERESIS_TEMP, 53 .min_state = 0, 54 .max_state = (4 * MLXSW_THERMAL_MAX_STATE) / 10, 55 }, 56 { 57 /* In range - 40-100% PWM */ 58 .type = THERMAL_TRIP_ACTIVE, 59 .temp = MLXSW_THERMAL_ASIC_TEMP_HIGH, 60 .hyst = MLXSW_THERMAL_HYSTERESIS_TEMP, 61 .min_state = (4 * MLXSW_THERMAL_MAX_STATE) / 10, 62 .max_state = MLXSW_THERMAL_MAX_STATE, 63 }, 64 { /* Warning */ 65 .type = THERMAL_TRIP_HOT, 66 .temp = MLXSW_THERMAL_ASIC_TEMP_HOT, 67 .min_state = MLXSW_THERMAL_MAX_STATE, 68 .max_state = MLXSW_THERMAL_MAX_STATE, 69 }, 70}; 71 72#define MLXSW_THERMAL_NUM_TRIPS ARRAY_SIZE(default_thermal_trips) 73 74/* Make sure all trips are writable */ 75#define MLXSW_THERMAL_TRIP_MASK (BIT(MLXSW_THERMAL_NUM_TRIPS) - 1) 76 77struct mlxsw_thermal; 78 79struct mlxsw_thermal_module { 80 struct mlxsw_thermal *parent; 81 struct thermal_zone_device *tzdev; 82 struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS]; 83 int module; /* Module or gearbox number */ 84 u8 slot_index; 85}; 86 87struct mlxsw_thermal_area { 88 struct mlxsw_thermal_module *tz_module_arr; 89 u8 tz_module_num; 90 struct mlxsw_thermal_module *tz_gearbox_arr; 91 u8 tz_gearbox_num; 92 u8 slot_index; 93 bool active; 94}; 95 96struct mlxsw_thermal { 97 struct mlxsw_core *core; 98 const struct mlxsw_bus_info *bus_info; 99 struct thermal_zone_device *tzdev; 100 int polling_delay; 101 struct thermal_cooling_device *cdevs[MLXSW_MFCR_PWMS_MAX]; 102 u8 cooling_levels[MLXSW_THERMAL_MAX_STATE + 1]; 103 struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS]; 104 unsigned int tz_highest_score; 105 struct thermal_zone_device *tz_highest_dev; 106 struct mlxsw_thermal_area line_cards[]; 107}; 108 109static inline u8 mlxsw_state_to_duty(int state) 110{ 111 return DIV_ROUND_CLOSEST(state * MLXSW_THERMAL_MAX_DUTY, 112 MLXSW_THERMAL_MAX_STATE); 113} 114 115static inline int mlxsw_duty_to_state(u8 duty) 116{ 117 return DIV_ROUND_CLOSEST(duty * MLXSW_THERMAL_MAX_STATE, 118 MLXSW_THERMAL_MAX_DUTY); 119} 120 121static int mlxsw_get_cooling_device_idx(struct mlxsw_thermal *thermal, 122 struct thermal_cooling_device *cdev) 123{ 124 int i; 125 126 for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++) 127 if (thermal->cdevs[i] == cdev) 128 return i; 129 130 /* Allow mlxsw thermal zone binding to an external cooling device */ 131 for (i = 0; i < ARRAY_SIZE(mlxsw_thermal_external_allowed_cdev); i++) { 132 if (!strcmp(cdev->type, mlxsw_thermal_external_allowed_cdev[i])) 133 return 0; 134 } 135 136 return -ENODEV; 137} 138 139static void 140mlxsw_thermal_module_trips_reset(struct mlxsw_thermal_module *tz) 141{ 142 tz->trips[MLXSW_THERMAL_TEMP_TRIP_NORM].temp = 0; 143 tz->trips[MLXSW_THERMAL_TEMP_TRIP_HIGH].temp = 0; 144 tz->trips[MLXSW_THERMAL_TEMP_TRIP_HOT].temp = 0; 145} 146 147static int 148mlxsw_thermal_module_trips_update(struct device *dev, struct mlxsw_core *core, 149 struct mlxsw_thermal_module *tz, 150 int crit_temp, int emerg_temp) 151{ 152 int err; 153 154 /* Do not try to query temperature thresholds directly from the module's 155 * EEPROM if we got valid thresholds from MTMP. 156 */ 157 if (!emerg_temp || !crit_temp) { 158 err = mlxsw_env_module_temp_thresholds_get(core, tz->slot_index, 159 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->slot_index, 166 tz->module, 167 SFP_TEMP_HIGH_ALARM, 168 &emerg_temp); 169 if (err) 170 return err; 171 } 172 173 if (crit_temp > emerg_temp) { 174 dev_warn(dev, "%s : Critical threshold %d is above emergency threshold %d\n", 175 tz->tzdev->type, crit_temp, emerg_temp); 176 return 0; 177 } 178 179 /* According to the system thermal requirements, the thermal zones are 180 * defined with three trip points. The critical and emergency 181 * temperature thresholds, provided by QSFP module are set as "active" 182 * and "hot" trip points, "normal" trip point is derived from "active" 183 * by subtracting double hysteresis value. 184 */ 185 if (crit_temp >= MLXSW_THERMAL_MODULE_TEMP_SHIFT) 186 tz->trips[MLXSW_THERMAL_TEMP_TRIP_NORM].temp = crit_temp - 187 MLXSW_THERMAL_MODULE_TEMP_SHIFT; 188 else 189 tz->trips[MLXSW_THERMAL_TEMP_TRIP_NORM].temp = crit_temp; 190 tz->trips[MLXSW_THERMAL_TEMP_TRIP_HIGH].temp = crit_temp; 191 tz->trips[MLXSW_THERMAL_TEMP_TRIP_HOT].temp = emerg_temp; 192 193 return 0; 194} 195 196static void mlxsw_thermal_tz_score_update(struct mlxsw_thermal *thermal, 197 struct thermal_zone_device *tzdev, 198 struct mlxsw_thermal_trip *trips, 199 int temp) 200{ 201 struct mlxsw_thermal_trip *trip = trips; 202 unsigned int score, delta, i, shift = 1; 203 204 /* Calculate thermal zone score, if temperature is above the hot 205 * threshold score is set to MLXSW_THERMAL_TEMP_SCORE_MAX. 206 */ 207 score = MLXSW_THERMAL_TEMP_SCORE_MAX; 208 for (i = MLXSW_THERMAL_TEMP_TRIP_NORM; i < MLXSW_THERMAL_NUM_TRIPS; 209 i++, trip++) { 210 if (temp < trip->temp) { 211 delta = DIV_ROUND_CLOSEST(temp, trip->temp - temp); 212 score = delta * shift; 213 break; 214 } 215 shift *= 256; 216 } 217 218 if (score > thermal->tz_highest_score) { 219 thermal->tz_highest_score = score; 220 thermal->tz_highest_dev = tzdev; 221 } 222} 223 224static int mlxsw_thermal_bind(struct thermal_zone_device *tzdev, 225 struct thermal_cooling_device *cdev) 226{ 227 struct mlxsw_thermal *thermal = tzdev->devdata; 228 struct device *dev = thermal->bus_info->dev; 229 int i, err; 230 231 /* If the cooling device is one of ours bind it */ 232 if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0) 233 return 0; 234 235 for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) { 236 const struct mlxsw_thermal_trip *trip = &thermal->trips[i]; 237 238 err = thermal_zone_bind_cooling_device(tzdev, i, cdev, 239 trip->max_state, 240 trip->min_state, 241 THERMAL_WEIGHT_DEFAULT); 242 if (err < 0) { 243 dev_err(dev, "Failed to bind cooling device to trip %d\n", i); 244 return err; 245 } 246 } 247 return 0; 248} 249 250static int mlxsw_thermal_unbind(struct thermal_zone_device *tzdev, 251 struct thermal_cooling_device *cdev) 252{ 253 struct mlxsw_thermal *thermal = tzdev->devdata; 254 struct device *dev = thermal->bus_info->dev; 255 int i; 256 int err; 257 258 /* If the cooling device is our one unbind it */ 259 if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0) 260 return 0; 261 262 for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) { 263 err = thermal_zone_unbind_cooling_device(tzdev, i, cdev); 264 if (err < 0) { 265 dev_err(dev, "Failed to unbind cooling device\n"); 266 return err; 267 } 268 } 269 return 0; 270} 271 272static int mlxsw_thermal_get_temp(struct thermal_zone_device *tzdev, 273 int *p_temp) 274{ 275 struct mlxsw_thermal *thermal = tzdev->devdata; 276 struct device *dev = thermal->bus_info->dev; 277 char mtmp_pl[MLXSW_REG_MTMP_LEN]; 278 int temp; 279 int err; 280 281 mlxsw_reg_mtmp_pack(mtmp_pl, 0, 0, false, false); 282 283 err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl); 284 if (err) { 285 dev_err(dev, "Failed to query temp sensor\n"); 286 return err; 287 } 288 mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL, NULL, NULL); 289 if (temp > 0) 290 mlxsw_thermal_tz_score_update(thermal, tzdev, thermal->trips, 291 temp); 292 293 *p_temp = temp; 294 return 0; 295} 296 297static int mlxsw_thermal_get_trip_type(struct thermal_zone_device *tzdev, 298 int trip, 299 enum thermal_trip_type *p_type) 300{ 301 struct mlxsw_thermal *thermal = tzdev->devdata; 302 303 if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS) 304 return -EINVAL; 305 306 *p_type = thermal->trips[trip].type; 307 return 0; 308} 309 310static int mlxsw_thermal_get_trip_temp(struct thermal_zone_device *tzdev, 311 int trip, int *p_temp) 312{ 313 struct mlxsw_thermal *thermal = tzdev->devdata; 314 315 if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS) 316 return -EINVAL; 317 318 *p_temp = thermal->trips[trip].temp; 319 return 0; 320} 321 322static int mlxsw_thermal_set_trip_temp(struct thermal_zone_device *tzdev, 323 int trip, int temp) 324{ 325 struct mlxsw_thermal *thermal = tzdev->devdata; 326 327 if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS) 328 return -EINVAL; 329 330 thermal->trips[trip].temp = temp; 331 return 0; 332} 333 334static int mlxsw_thermal_get_trip_hyst(struct thermal_zone_device *tzdev, 335 int trip, int *p_hyst) 336{ 337 struct mlxsw_thermal *thermal = tzdev->devdata; 338 339 *p_hyst = thermal->trips[trip].hyst; 340 return 0; 341} 342 343static int mlxsw_thermal_set_trip_hyst(struct thermal_zone_device *tzdev, 344 int trip, int hyst) 345{ 346 struct mlxsw_thermal *thermal = tzdev->devdata; 347 348 thermal->trips[trip].hyst = hyst; 349 return 0; 350} 351 352static int mlxsw_thermal_trend_get(struct thermal_zone_device *tzdev, 353 int trip, enum thermal_trend *trend) 354{ 355 struct mlxsw_thermal *thermal = tzdev->devdata; 356 357 if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS) 358 return -EINVAL; 359 360 if (tzdev == thermal->tz_highest_dev) 361 return 1; 362 363 *trend = THERMAL_TREND_STABLE; 364 return 0; 365} 366 367static struct thermal_zone_params mlxsw_thermal_params = { 368 .no_hwmon = true, 369}; 370 371static struct thermal_zone_device_ops mlxsw_thermal_ops = { 372 .bind = mlxsw_thermal_bind, 373 .unbind = mlxsw_thermal_unbind, 374 .get_temp = mlxsw_thermal_get_temp, 375 .get_trip_type = mlxsw_thermal_get_trip_type, 376 .get_trip_temp = mlxsw_thermal_get_trip_temp, 377 .set_trip_temp = mlxsw_thermal_set_trip_temp, 378 .get_trip_hyst = mlxsw_thermal_get_trip_hyst, 379 .set_trip_hyst = mlxsw_thermal_set_trip_hyst, 380 .get_trend = mlxsw_thermal_trend_get, 381}; 382 383static int mlxsw_thermal_module_bind(struct thermal_zone_device *tzdev, 384 struct thermal_cooling_device *cdev) 385{ 386 struct mlxsw_thermal_module *tz = tzdev->devdata; 387 struct mlxsw_thermal *thermal = tz->parent; 388 int i, j, err; 389 390 /* If the cooling device is one of ours bind it */ 391 if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0) 392 return 0; 393 394 for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) { 395 const struct mlxsw_thermal_trip *trip = &tz->trips[i]; 396 397 err = thermal_zone_bind_cooling_device(tzdev, i, cdev, 398 trip->max_state, 399 trip->min_state, 400 THERMAL_WEIGHT_DEFAULT); 401 if (err < 0) 402 goto err_thermal_zone_bind_cooling_device; 403 } 404 return 0; 405 406err_thermal_zone_bind_cooling_device: 407 for (j = i - 1; j >= 0; j--) 408 thermal_zone_unbind_cooling_device(tzdev, j, cdev); 409 return err; 410} 411 412static int mlxsw_thermal_module_unbind(struct thermal_zone_device *tzdev, 413 struct thermal_cooling_device *cdev) 414{ 415 struct mlxsw_thermal_module *tz = tzdev->devdata; 416 struct mlxsw_thermal *thermal = tz->parent; 417 int i; 418 int err; 419 420 /* If the cooling device is one of ours unbind it */ 421 if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0) 422 return 0; 423 424 for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) { 425 err = thermal_zone_unbind_cooling_device(tzdev, i, cdev); 426 WARN_ON(err); 427 } 428 return err; 429} 430 431static void 432mlxsw_thermal_module_temp_and_thresholds_get(struct mlxsw_core *core, 433 u8 slot_index, u16 sensor_index, 434 int *p_temp, int *p_crit_temp, 435 int *p_emerg_temp) 436{ 437 char mtmp_pl[MLXSW_REG_MTMP_LEN]; 438 int err; 439 440 /* Read module temperature and thresholds. */ 441 mlxsw_reg_mtmp_pack(mtmp_pl, slot_index, sensor_index, 442 false, false); 443 err = mlxsw_reg_query(core, MLXSW_REG(mtmp), mtmp_pl); 444 if (err) { 445 /* Set temperature and thresholds to zero to avoid passing 446 * uninitialized data back to the caller. 447 */ 448 *p_temp = 0; 449 *p_crit_temp = 0; 450 *p_emerg_temp = 0; 451 452 return; 453 } 454 mlxsw_reg_mtmp_unpack(mtmp_pl, p_temp, NULL, p_crit_temp, p_emerg_temp, 455 NULL); 456} 457 458static int mlxsw_thermal_module_temp_get(struct thermal_zone_device *tzdev, 459 int *p_temp) 460{ 461 struct mlxsw_thermal_module *tz = tzdev->devdata; 462 struct mlxsw_thermal *thermal = tz->parent; 463 int temp, crit_temp, emerg_temp; 464 struct device *dev; 465 u16 sensor_index; 466 int err; 467 468 dev = thermal->bus_info->dev; 469 sensor_index = MLXSW_REG_MTMP_MODULE_INDEX_MIN + tz->module; 470 471 /* Read module temperature and thresholds. */ 472 mlxsw_thermal_module_temp_and_thresholds_get(thermal->core, 473 tz->slot_index, 474 sensor_index, &temp, 475 &crit_temp, &emerg_temp); 476 *p_temp = temp; 477 478 if (!temp) 479 return 0; 480 481 /* Update trip points. */ 482 err = mlxsw_thermal_module_trips_update(dev, thermal->core, tz, 483 crit_temp, emerg_temp); 484 if (!err && temp > 0) 485 mlxsw_thermal_tz_score_update(thermal, tzdev, tz->trips, temp); 486 487 return 0; 488} 489 490static int 491mlxsw_thermal_module_trip_type_get(struct thermal_zone_device *tzdev, int trip, 492 enum thermal_trip_type *p_type) 493{ 494 struct mlxsw_thermal_module *tz = tzdev->devdata; 495 496 if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS) 497 return -EINVAL; 498 499 *p_type = tz->trips[trip].type; 500 return 0; 501} 502 503static int 504mlxsw_thermal_module_trip_temp_get(struct thermal_zone_device *tzdev, 505 int trip, int *p_temp) 506{ 507 struct mlxsw_thermal_module *tz = tzdev->devdata; 508 509 if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS) 510 return -EINVAL; 511 512 *p_temp = tz->trips[trip].temp; 513 return 0; 514} 515 516static int 517mlxsw_thermal_module_trip_temp_set(struct thermal_zone_device *tzdev, 518 int trip, int temp) 519{ 520 struct mlxsw_thermal_module *tz = tzdev->devdata; 521 522 if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS) 523 return -EINVAL; 524 525 tz->trips[trip].temp = temp; 526 return 0; 527} 528 529static int 530mlxsw_thermal_module_trip_hyst_get(struct thermal_zone_device *tzdev, int trip, 531 int *p_hyst) 532{ 533 struct mlxsw_thermal_module *tz = tzdev->devdata; 534 535 *p_hyst = tz->trips[trip].hyst; 536 return 0; 537} 538 539static int 540mlxsw_thermal_module_trip_hyst_set(struct thermal_zone_device *tzdev, int trip, 541 int hyst) 542{ 543 struct mlxsw_thermal_module *tz = tzdev->devdata; 544 545 tz->trips[trip].hyst = hyst; 546 return 0; 547} 548 549static int mlxsw_thermal_module_trend_get(struct thermal_zone_device *tzdev, 550 int trip, enum thermal_trend *trend) 551{ 552 struct mlxsw_thermal_module *tz = tzdev->devdata; 553 struct mlxsw_thermal *thermal = tz->parent; 554 555 if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS) 556 return -EINVAL; 557 558 if (tzdev == thermal->tz_highest_dev) 559 return 1; 560 561 *trend = THERMAL_TREND_STABLE; 562 return 0; 563} 564 565static struct thermal_zone_device_ops mlxsw_thermal_module_ops = { 566 .bind = mlxsw_thermal_module_bind, 567 .unbind = mlxsw_thermal_module_unbind, 568 .get_temp = mlxsw_thermal_module_temp_get, 569 .get_trip_type = mlxsw_thermal_module_trip_type_get, 570 .get_trip_temp = mlxsw_thermal_module_trip_temp_get, 571 .set_trip_temp = mlxsw_thermal_module_trip_temp_set, 572 .get_trip_hyst = mlxsw_thermal_module_trip_hyst_get, 573 .set_trip_hyst = mlxsw_thermal_module_trip_hyst_set, 574 .get_trend = mlxsw_thermal_module_trend_get, 575}; 576 577static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev, 578 int *p_temp) 579{ 580 struct mlxsw_thermal_module *tz = tzdev->devdata; 581 struct mlxsw_thermal *thermal = tz->parent; 582 char mtmp_pl[MLXSW_REG_MTMP_LEN]; 583 u16 index; 584 int temp; 585 int err; 586 587 index = MLXSW_REG_MTMP_GBOX_INDEX_MIN + tz->module; 588 mlxsw_reg_mtmp_pack(mtmp_pl, tz->slot_index, index, false, false); 589 590 err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl); 591 if (err) 592 return err; 593 594 mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL, NULL, NULL); 595 if (temp > 0) 596 mlxsw_thermal_tz_score_update(thermal, tzdev, tz->trips, temp); 597 598 *p_temp = temp; 599 return 0; 600} 601 602static struct thermal_zone_device_ops mlxsw_thermal_gearbox_ops = { 603 .bind = mlxsw_thermal_module_bind, 604 .unbind = mlxsw_thermal_module_unbind, 605 .get_temp = mlxsw_thermal_gearbox_temp_get, 606 .get_trip_type = mlxsw_thermal_module_trip_type_get, 607 .get_trip_temp = mlxsw_thermal_module_trip_temp_get, 608 .set_trip_temp = mlxsw_thermal_module_trip_temp_set, 609 .get_trip_hyst = mlxsw_thermal_module_trip_hyst_get, 610 .set_trip_hyst = mlxsw_thermal_module_trip_hyst_set, 611 .get_trend = mlxsw_thermal_module_trend_get, 612}; 613 614static int mlxsw_thermal_get_max_state(struct thermal_cooling_device *cdev, 615 unsigned long *p_state) 616{ 617 *p_state = MLXSW_THERMAL_MAX_STATE; 618 return 0; 619} 620 621static int mlxsw_thermal_get_cur_state(struct thermal_cooling_device *cdev, 622 unsigned long *p_state) 623 624{ 625 struct mlxsw_thermal *thermal = cdev->devdata; 626 struct device *dev = thermal->bus_info->dev; 627 char mfsc_pl[MLXSW_REG_MFSC_LEN]; 628 int err, idx; 629 u8 duty; 630 631 idx = mlxsw_get_cooling_device_idx(thermal, cdev); 632 if (idx < 0) 633 return idx; 634 635 mlxsw_reg_mfsc_pack(mfsc_pl, idx, 0); 636 err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfsc), mfsc_pl); 637 if (err) { 638 dev_err(dev, "Failed to query PWM duty\n"); 639 return err; 640 } 641 642 duty = mlxsw_reg_mfsc_pwm_duty_cycle_get(mfsc_pl); 643 *p_state = mlxsw_duty_to_state(duty); 644 return 0; 645} 646 647static int mlxsw_thermal_set_cur_state(struct thermal_cooling_device *cdev, 648 unsigned long state) 649 650{ 651 struct mlxsw_thermal *thermal = cdev->devdata; 652 struct device *dev = thermal->bus_info->dev; 653 char mfsc_pl[MLXSW_REG_MFSC_LEN]; 654 int idx; 655 int err; 656 657 if (state > MLXSW_THERMAL_MAX_STATE) 658 return -EINVAL; 659 660 idx = mlxsw_get_cooling_device_idx(thermal, cdev); 661 if (idx < 0) 662 return idx; 663 664 /* Normalize the state to the valid speed range. */ 665 state = thermal->cooling_levels[state]; 666 mlxsw_reg_mfsc_pack(mfsc_pl, idx, mlxsw_state_to_duty(state)); 667 err = mlxsw_reg_write(thermal->core, MLXSW_REG(mfsc), mfsc_pl); 668 if (err) { 669 dev_err(dev, "Failed to write PWM duty\n"); 670 return err; 671 } 672 return 0; 673} 674 675static const struct thermal_cooling_device_ops mlxsw_cooling_ops = { 676 .get_max_state = mlxsw_thermal_get_max_state, 677 .get_cur_state = mlxsw_thermal_get_cur_state, 678 .set_cur_state = mlxsw_thermal_set_cur_state, 679}; 680 681static int 682mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz) 683{ 684 char tz_name[THERMAL_NAME_LENGTH]; 685 int err; 686 687 if (module_tz->slot_index) 688 snprintf(tz_name, sizeof(tz_name), "mlxsw-lc%d-module%d", 689 module_tz->slot_index, module_tz->module + 1); 690 else 691 snprintf(tz_name, sizeof(tz_name), "mlxsw-module%d", 692 module_tz->module + 1); 693 module_tz->tzdev = thermal_zone_device_register(tz_name, 694 MLXSW_THERMAL_NUM_TRIPS, 695 MLXSW_THERMAL_TRIP_MASK, 696 module_tz, 697 &mlxsw_thermal_module_ops, 698 &mlxsw_thermal_params, 699 0, 700 module_tz->parent->polling_delay); 701 if (IS_ERR(module_tz->tzdev)) { 702 err = PTR_ERR(module_tz->tzdev); 703 return err; 704 } 705 706 err = thermal_zone_device_enable(module_tz->tzdev); 707 if (err) 708 thermal_zone_device_unregister(module_tz->tzdev); 709 710 return err; 711} 712 713static void mlxsw_thermal_module_tz_fini(struct thermal_zone_device *tzdev) 714{ 715 thermal_zone_device_unregister(tzdev); 716} 717 718static int 719mlxsw_thermal_module_init(struct device *dev, struct mlxsw_core *core, 720 struct mlxsw_thermal *thermal, 721 struct mlxsw_thermal_area *area, u8 module) 722{ 723 struct mlxsw_thermal_module *module_tz; 724 int dummy_temp, crit_temp, emerg_temp; 725 u16 sensor_index; 726 727 sensor_index = MLXSW_REG_MTMP_MODULE_INDEX_MIN + module; 728 module_tz = &area->tz_module_arr[module]; 729 /* Skip if parent is already set (case of port split). */ 730 if (module_tz->parent) 731 return 0; 732 module_tz->module = module; 733 module_tz->slot_index = area->slot_index; 734 module_tz->parent = thermal; 735 memcpy(module_tz->trips, default_thermal_trips, 736 sizeof(thermal->trips)); 737 /* Initialize all trip point. */ 738 mlxsw_thermal_module_trips_reset(module_tz); 739 /* Read module temperature and thresholds. */ 740 mlxsw_thermal_module_temp_and_thresholds_get(core, area->slot_index, 741 sensor_index, &dummy_temp, 742 &crit_temp, &emerg_temp); 743 /* Update trip point according to the module data. */ 744 return mlxsw_thermal_module_trips_update(dev, core, module_tz, 745 crit_temp, emerg_temp); 746} 747 748static void mlxsw_thermal_module_fini(struct mlxsw_thermal_module *module_tz) 749{ 750 if (module_tz && module_tz->tzdev) { 751 mlxsw_thermal_module_tz_fini(module_tz->tzdev); 752 module_tz->tzdev = NULL; 753 module_tz->parent = NULL; 754 } 755} 756 757static int 758mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core, 759 struct mlxsw_thermal *thermal, 760 struct mlxsw_thermal_area *area) 761{ 762 struct mlxsw_thermal_module *module_tz; 763 char mgpir_pl[MLXSW_REG_MGPIR_LEN]; 764 int i, err; 765 766 mlxsw_reg_mgpir_pack(mgpir_pl, area->slot_index); 767 err = mlxsw_reg_query(core, MLXSW_REG(mgpir), mgpir_pl); 768 if (err) 769 return err; 770 771 mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, 772 &area->tz_module_num, NULL); 773 774 /* For modular system module counter could be zero. */ 775 if (!area->tz_module_num) 776 return 0; 777 778 area->tz_module_arr = kcalloc(area->tz_module_num, 779 sizeof(*area->tz_module_arr), 780 GFP_KERNEL); 781 if (!area->tz_module_arr) 782 return -ENOMEM; 783 784 for (i = 0; i < area->tz_module_num; i++) { 785 err = mlxsw_thermal_module_init(dev, core, thermal, area, i); 786 if (err) 787 goto err_thermal_module_init; 788 } 789 790 for (i = 0; i < area->tz_module_num; i++) { 791 module_tz = &area->tz_module_arr[i]; 792 if (!module_tz->parent) 793 continue; 794 err = mlxsw_thermal_module_tz_init(module_tz); 795 if (err) 796 goto err_thermal_module_tz_init; 797 } 798 799 return 0; 800 801err_thermal_module_tz_init: 802err_thermal_module_init: 803 for (i = area->tz_module_num - 1; i >= 0; i--) 804 mlxsw_thermal_module_fini(&area->tz_module_arr[i]); 805 kfree(area->tz_module_arr); 806 return err; 807} 808 809static void 810mlxsw_thermal_modules_fini(struct mlxsw_thermal *thermal, 811 struct mlxsw_thermal_area *area) 812{ 813 int i; 814 815 for (i = area->tz_module_num - 1; i >= 0; i--) 816 mlxsw_thermal_module_fini(&area->tz_module_arr[i]); 817 kfree(area->tz_module_arr); 818} 819 820static int 821mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz) 822{ 823 char tz_name[THERMAL_NAME_LENGTH]; 824 int ret; 825 826 if (gearbox_tz->slot_index) 827 snprintf(tz_name, sizeof(tz_name), "mlxsw-lc%d-gearbox%d", 828 gearbox_tz->slot_index, gearbox_tz->module + 1); 829 else 830 snprintf(tz_name, sizeof(tz_name), "mlxsw-gearbox%d", 831 gearbox_tz->module + 1); 832 gearbox_tz->tzdev = thermal_zone_device_register(tz_name, 833 MLXSW_THERMAL_NUM_TRIPS, 834 MLXSW_THERMAL_TRIP_MASK, 835 gearbox_tz, 836 &mlxsw_thermal_gearbox_ops, 837 &mlxsw_thermal_params, 0, 838 gearbox_tz->parent->polling_delay); 839 if (IS_ERR(gearbox_tz->tzdev)) 840 return PTR_ERR(gearbox_tz->tzdev); 841 842 ret = thermal_zone_device_enable(gearbox_tz->tzdev); 843 if (ret) 844 thermal_zone_device_unregister(gearbox_tz->tzdev); 845 846 return ret; 847} 848 849static void 850mlxsw_thermal_gearbox_tz_fini(struct mlxsw_thermal_module *gearbox_tz) 851{ 852 thermal_zone_device_unregister(gearbox_tz->tzdev); 853} 854 855static int 856mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core, 857 struct mlxsw_thermal *thermal, 858 struct mlxsw_thermal_area *area) 859{ 860 enum mlxsw_reg_mgpir_device_type device_type; 861 struct mlxsw_thermal_module *gearbox_tz; 862 char mgpir_pl[MLXSW_REG_MGPIR_LEN]; 863 u8 gbox_num; 864 int i; 865 int err; 866 867 mlxsw_reg_mgpir_pack(mgpir_pl, area->slot_index); 868 err = mlxsw_reg_query(core, MLXSW_REG(mgpir), mgpir_pl); 869 if (err) 870 return err; 871 872 mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, &device_type, NULL, 873 NULL, NULL); 874 if (device_type != MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE || 875 !gbox_num) 876 return 0; 877 878 area->tz_gearbox_num = gbox_num; 879 area->tz_gearbox_arr = kcalloc(area->tz_gearbox_num, 880 sizeof(*area->tz_gearbox_arr), 881 GFP_KERNEL); 882 if (!area->tz_gearbox_arr) 883 return -ENOMEM; 884 885 for (i = 0; i < area->tz_gearbox_num; i++) { 886 gearbox_tz = &area->tz_gearbox_arr[i]; 887 memcpy(gearbox_tz->trips, default_thermal_trips, 888 sizeof(thermal->trips)); 889 gearbox_tz->module = i; 890 gearbox_tz->parent = thermal; 891 gearbox_tz->slot_index = area->slot_index; 892 err = mlxsw_thermal_gearbox_tz_init(gearbox_tz); 893 if (err) 894 goto err_thermal_gearbox_tz_init; 895 } 896 897 return 0; 898 899err_thermal_gearbox_tz_init: 900 for (i--; i >= 0; i--) 901 mlxsw_thermal_gearbox_tz_fini(&area->tz_gearbox_arr[i]); 902 kfree(area->tz_gearbox_arr); 903 return err; 904} 905 906static void 907mlxsw_thermal_gearboxes_fini(struct mlxsw_thermal *thermal, 908 struct mlxsw_thermal_area *area) 909{ 910 int i; 911 912 for (i = area->tz_gearbox_num - 1; i >= 0; i--) 913 mlxsw_thermal_gearbox_tz_fini(&area->tz_gearbox_arr[i]); 914 kfree(area->tz_gearbox_arr); 915} 916 917static void 918mlxsw_thermal_got_active(struct mlxsw_core *mlxsw_core, u8 slot_index, 919 void *priv) 920{ 921 struct mlxsw_thermal *thermal = priv; 922 struct mlxsw_thermal_area *linecard; 923 int err; 924 925 linecard = &thermal->line_cards[slot_index]; 926 927 if (linecard->active) 928 return; 929 930 linecard->slot_index = slot_index; 931 err = mlxsw_thermal_modules_init(thermal->bus_info->dev, thermal->core, 932 thermal, linecard); 933 if (err) { 934 dev_err(thermal->bus_info->dev, "Failed to configure thermal objects for line card modules in slot %d\n", 935 slot_index); 936 return; 937 } 938 939 err = mlxsw_thermal_gearboxes_init(thermal->bus_info->dev, 940 thermal->core, thermal, linecard); 941 if (err) { 942 dev_err(thermal->bus_info->dev, "Failed to configure thermal objects for line card gearboxes in slot %d\n", 943 slot_index); 944 goto err_thermal_linecard_gearboxes_init; 945 } 946 947 linecard->active = true; 948 949 return; 950 951err_thermal_linecard_gearboxes_init: 952 mlxsw_thermal_modules_fini(thermal, linecard); 953} 954 955static void 956mlxsw_thermal_got_inactive(struct mlxsw_core *mlxsw_core, u8 slot_index, 957 void *priv) 958{ 959 struct mlxsw_thermal *thermal = priv; 960 struct mlxsw_thermal_area *linecard; 961 962 linecard = &thermal->line_cards[slot_index]; 963 if (!linecard->active) 964 return; 965 linecard->active = false; 966 mlxsw_thermal_gearboxes_fini(thermal, linecard); 967 mlxsw_thermal_modules_fini(thermal, linecard); 968} 969 970static struct mlxsw_linecards_event_ops mlxsw_thermal_event_ops = { 971 .got_active = mlxsw_thermal_got_active, 972 .got_inactive = mlxsw_thermal_got_inactive, 973}; 974 975int mlxsw_thermal_init(struct mlxsw_core *core, 976 const struct mlxsw_bus_info *bus_info, 977 struct mlxsw_thermal **p_thermal) 978{ 979 char mfcr_pl[MLXSW_REG_MFCR_LEN] = { 0 }; 980 enum mlxsw_reg_mfcr_pwm_frequency freq; 981 struct device *dev = bus_info->dev; 982 char mgpir_pl[MLXSW_REG_MGPIR_LEN]; 983 struct mlxsw_thermal *thermal; 984 u8 pwm_active, num_of_slots; 985 u16 tacho_active; 986 int err, i; 987 988 mlxsw_reg_mgpir_pack(mgpir_pl, 0); 989 err = mlxsw_reg_query(core, MLXSW_REG(mgpir), mgpir_pl); 990 if (err) 991 return err; 992 993 mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, NULL, 994 &num_of_slots); 995 996 thermal = kzalloc(struct_size(thermal, line_cards, num_of_slots + 1), 997 GFP_KERNEL); 998 if (!thermal) 999 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 /* We need to query the register to preserve maximum */ 1020 err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfsl), 1021 mfsl_pl); 1022 if (err) 1023 goto err_reg_query; 1024 1025 /* set the minimal RPMs to 0 */ 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 /* Initialize cooling levels per PWM state. */ 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 1094err_thermal_zone_device_enable: 1095 mlxsw_linecards_event_ops_unregister(thermal->core, 1096 &mlxsw_thermal_event_ops, 1097 thermal); 1098err_linecards_event_ops_register: 1099 mlxsw_thermal_gearboxes_fini(thermal, &thermal->line_cards[0]); 1100err_thermal_gearboxes_init: 1101 mlxsw_thermal_modules_fini(thermal, &thermal->line_cards[0]); 1102err_thermal_modules_init: 1103 if (thermal->tzdev) { 1104 thermal_zone_device_unregister(thermal->tzdev); 1105 thermal->tzdev = NULL; 1106 } 1107err_thermal_zone_device_register: 1108err_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]); 1112err_reg_write: 1113err_reg_query: 1114 kfree(thermal); 1115 return err; 1116} 1117 1118void 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}