786 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/* Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved3 * 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 1028#define MLXSW_THERMAL_MIN_STATE 229#define MLXSW_THERMAL_MAX_DUTY 25530 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 struct thermal_zone_params mlxsw_thermal_params = {209 .no_hwmon = true,210};211 212static 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 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 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 int350mlxsw_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 else359 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 int387mlxsw_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 int415mlxsw_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 void456mlxsw_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 int467mlxsw_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 else476 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 void496mlxsw_thermal_gearbox_tz_fini(struct mlxsw_thermal_module *gearbox_tz)497{498 thermal_zone_device_unregister(gearbox_tz->tzdev);499}500 501static int502mlxsw_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 void558mlxsw_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 void569mlxsw_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 void607mlxsw_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}786