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