19948a064SJiri Pirko // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 29948a064SJiri Pirko /* Copyright (c) 2015-2018 Mellanox Technologies. All rights reserved */ 389309da3SJiri Pirko 489309da3SJiri Pirko #include <linux/kernel.h> 589309da3SJiri Pirko #include <linux/types.h> 689309da3SJiri Pirko #include <linux/device.h> 789309da3SJiri Pirko #include <linux/sysfs.h> 889309da3SJiri Pirko #include <linux/hwmon.h> 989309da3SJiri Pirko #include <linux/err.h> 105c42eaa0SVadim Pasternak #include <linux/sfp.h> 1189309da3SJiri Pirko 1289309da3SJiri Pirko #include "core.h" 135c42eaa0SVadim Pasternak #include "core_env.h" 1489309da3SJiri Pirko 1502bed4e8SAmit Cohen #define MLXSW_HWMON_SENSORS_MAX_COUNT 64 1602bed4e8SAmit Cohen #define MLXSW_HWMON_MODULES_MAX_COUNT 64 1702bed4e8SAmit Cohen #define MLXSW_HWMON_GEARBOXES_MAX_COUNT 32 1802bed4e8SAmit Cohen 1902bed4e8SAmit Cohen #define MLXSW_HWMON_ATTR_PER_SENSOR 3 2091df5d3aSAmit Cohen #define MLXSW_HWMON_ATTR_PER_MODULE 7 2102bed4e8SAmit Cohen #define MLXSW_HWMON_ATTR_PER_GEARBOX 4 2202bed4e8SAmit Cohen 2302bed4e8SAmit Cohen #define MLXSW_HWMON_ATTR_COUNT (MLXSW_HWMON_SENSORS_MAX_COUNT * MLXSW_HWMON_ATTR_PER_SENSOR + \ 2402bed4e8SAmit Cohen MLXSW_HWMON_MODULES_MAX_COUNT * MLXSW_HWMON_ATTR_PER_MODULE + \ 2502bed4e8SAmit Cohen MLXSW_HWMON_GEARBOXES_MAX_COUNT * MLXSW_HWMON_ATTR_PER_GEARBOX + \ 2652581961SJiri Pirko MLXSW_MFCR_TACHOS_MAX + MLXSW_MFCR_PWMS_MAX) 2789309da3SJiri Pirko 2889309da3SJiri Pirko struct mlxsw_hwmon_attr { 2989309da3SJiri Pirko struct device_attribute dev_attr; 3089309da3SJiri Pirko struct mlxsw_hwmon *hwmon; 3189309da3SJiri Pirko unsigned int type_index; 32e7bc73cbSJiri Pirko char name[32]; 3389309da3SJiri Pirko }; 3489309da3SJiri Pirko 352e265a8bSVadim Pasternak static int mlxsw_hwmon_get_attr_index(int index, int count) 362e265a8bSVadim Pasternak { 372e265a8bSVadim Pasternak if (index >= count) 382e265a8bSVadim Pasternak return index % count + MLXSW_REG_MTMP_GBOX_INDEX_MIN; 392e265a8bSVadim Pasternak 402e265a8bSVadim Pasternak return index; 412e265a8bSVadim Pasternak } 422e265a8bSVadim Pasternak 4389309da3SJiri Pirko struct mlxsw_hwmon { 4489309da3SJiri Pirko struct mlxsw_core *core; 4589309da3SJiri Pirko const struct mlxsw_bus_info *bus_info; 4689309da3SJiri Pirko struct device *hwmon_dev; 4789309da3SJiri Pirko struct attribute_group group; 4889309da3SJiri Pirko const struct attribute_group *groups[2]; 4989309da3SJiri Pirko struct attribute *attrs[MLXSW_HWMON_ATTR_COUNT + 1]; 5089309da3SJiri Pirko struct mlxsw_hwmon_attr hwmon_attrs[MLXSW_HWMON_ATTR_COUNT]; 5189309da3SJiri Pirko unsigned int attrs_count; 525c42eaa0SVadim Pasternak u8 sensor_count; 53ea30a92aSVadim Pasternak u8 module_sensor_max; 5489309da3SJiri Pirko }; 5589309da3SJiri Pirko 5689309da3SJiri Pirko static ssize_t mlxsw_hwmon_temp_show(struct device *dev, 5789309da3SJiri Pirko struct device_attribute *attr, 5889309da3SJiri Pirko char *buf) 5989309da3SJiri Pirko { 6089309da3SJiri Pirko struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = 6189309da3SJiri Pirko container_of(attr, struct mlxsw_hwmon_attr, dev_attr); 6289309da3SJiri Pirko struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; 6389309da3SJiri Pirko char mtmp_pl[MLXSW_REG_MTMP_LEN]; 64f485cc36SVadim Pasternak int temp, index; 6589309da3SJiri Pirko int err; 6689309da3SJiri Pirko 672e265a8bSVadim Pasternak index = mlxsw_hwmon_get_attr_index(mlwsw_hwmon_attr->type_index, 68ea30a92aSVadim Pasternak mlxsw_hwmon->module_sensor_max); 692e265a8bSVadim Pasternak mlxsw_reg_mtmp_pack(mtmp_pl, index, false, false); 7089309da3SJiri Pirko err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); 7189309da3SJiri Pirko if (err) { 7289309da3SJiri Pirko dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query temp sensor\n"); 7389309da3SJiri Pirko return err; 7489309da3SJiri Pirko } 75*314dbb19SMykola Kostenok mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL, NULL, NULL); 76f485cc36SVadim Pasternak return sprintf(buf, "%d\n", temp); 7789309da3SJiri Pirko } 7889309da3SJiri Pirko 7989309da3SJiri Pirko static ssize_t mlxsw_hwmon_temp_max_show(struct device *dev, 8089309da3SJiri Pirko struct device_attribute *attr, 8189309da3SJiri Pirko char *buf) 8289309da3SJiri Pirko { 8389309da3SJiri Pirko struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = 8489309da3SJiri Pirko container_of(attr, struct mlxsw_hwmon_attr, dev_attr); 8589309da3SJiri Pirko struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; 8689309da3SJiri Pirko char mtmp_pl[MLXSW_REG_MTMP_LEN]; 87f485cc36SVadim Pasternak int temp_max, index; 8889309da3SJiri Pirko int err; 8989309da3SJiri Pirko 902e265a8bSVadim Pasternak index = mlxsw_hwmon_get_attr_index(mlwsw_hwmon_attr->type_index, 91ea30a92aSVadim Pasternak mlxsw_hwmon->module_sensor_max); 922e265a8bSVadim Pasternak mlxsw_reg_mtmp_pack(mtmp_pl, index, false, false); 9389309da3SJiri Pirko err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); 9489309da3SJiri Pirko if (err) { 9589309da3SJiri Pirko dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query temp sensor\n"); 9689309da3SJiri Pirko return err; 9789309da3SJiri Pirko } 98*314dbb19SMykola Kostenok mlxsw_reg_mtmp_unpack(mtmp_pl, NULL, &temp_max, NULL, NULL, NULL); 99f485cc36SVadim Pasternak return sprintf(buf, "%d\n", temp_max); 10089309da3SJiri Pirko } 10189309da3SJiri Pirko 102e7bc73cbSJiri Pirko static ssize_t mlxsw_hwmon_temp_rst_store(struct device *dev, 103e7bc73cbSJiri Pirko struct device_attribute *attr, 104e7bc73cbSJiri Pirko const char *buf, size_t len) 105e7bc73cbSJiri Pirko { 106e7bc73cbSJiri Pirko struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = 107e7bc73cbSJiri Pirko container_of(attr, struct mlxsw_hwmon_attr, dev_attr); 108e7bc73cbSJiri Pirko struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; 109fb1292f8SAmit Cohen char mtmp_pl[MLXSW_REG_MTMP_LEN] = {0}; 110e7bc73cbSJiri Pirko unsigned long val; 1112e265a8bSVadim Pasternak int index; 112e7bc73cbSJiri Pirko int err; 113e7bc73cbSJiri Pirko 114e7bc73cbSJiri Pirko err = kstrtoul(buf, 10, &val); 115e7bc73cbSJiri Pirko if (err) 116e7bc73cbSJiri Pirko return err; 117e7bc73cbSJiri Pirko if (val != 1) 118e7bc73cbSJiri Pirko return -EINVAL; 119e7bc73cbSJiri Pirko 1202e265a8bSVadim Pasternak index = mlxsw_hwmon_get_attr_index(mlwsw_hwmon_attr->type_index, 121ea30a92aSVadim Pasternak mlxsw_hwmon->module_sensor_max); 122fb1292f8SAmit Cohen 123fb1292f8SAmit Cohen mlxsw_reg_mtmp_sensor_index_set(mtmp_pl, index); 124fb1292f8SAmit Cohen err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); 125fb1292f8SAmit Cohen if (err) 126fb1292f8SAmit Cohen return err; 127fb1292f8SAmit Cohen mlxsw_reg_mtmp_mte_set(mtmp_pl, true); 128fb1292f8SAmit Cohen mlxsw_reg_mtmp_mtr_set(mtmp_pl, true); 129e7bc73cbSJiri Pirko err = mlxsw_reg_write(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); 130e7bc73cbSJiri Pirko if (err) { 131e7bc73cbSJiri Pirko dev_err(mlxsw_hwmon->bus_info->dev, "Failed to reset temp sensor history\n"); 132e7bc73cbSJiri Pirko return err; 133e7bc73cbSJiri Pirko } 134719255d0SDan Carpenter return len; 135e7bc73cbSJiri Pirko } 136e7bc73cbSJiri Pirko 13752581961SJiri Pirko static ssize_t mlxsw_hwmon_fan_rpm_show(struct device *dev, 13852581961SJiri Pirko struct device_attribute *attr, 13952581961SJiri Pirko char *buf) 14052581961SJiri Pirko { 14152581961SJiri Pirko struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = 14252581961SJiri Pirko container_of(attr, struct mlxsw_hwmon_attr, dev_attr); 14352581961SJiri Pirko struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; 14452581961SJiri Pirko char mfsm_pl[MLXSW_REG_MFSM_LEN]; 14552581961SJiri Pirko int err; 14652581961SJiri Pirko 14752581961SJiri Pirko mlxsw_reg_mfsm_pack(mfsm_pl, mlwsw_hwmon_attr->type_index); 14852581961SJiri Pirko err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mfsm), mfsm_pl); 14952581961SJiri Pirko if (err) { 15052581961SJiri Pirko dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query fan\n"); 15152581961SJiri Pirko return err; 15252581961SJiri Pirko } 15352581961SJiri Pirko return sprintf(buf, "%u\n", mlxsw_reg_mfsm_rpm_get(mfsm_pl)); 15452581961SJiri Pirko } 15552581961SJiri Pirko 1562c6a33cdSVadim Pasternak static ssize_t mlxsw_hwmon_fan_fault_show(struct device *dev, 1572c6a33cdSVadim Pasternak struct device_attribute *attr, 1582c6a33cdSVadim Pasternak char *buf) 1592c6a33cdSVadim Pasternak { 1602c6a33cdSVadim Pasternak struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = 1612c6a33cdSVadim Pasternak container_of(attr, struct mlxsw_hwmon_attr, dev_attr); 1622c6a33cdSVadim Pasternak struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; 1632c6a33cdSVadim Pasternak char fore_pl[MLXSW_REG_FORE_LEN]; 1642c6a33cdSVadim Pasternak bool fault; 1652c6a33cdSVadim Pasternak int err; 1662c6a33cdSVadim Pasternak 1672c6a33cdSVadim Pasternak err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(fore), fore_pl); 1682c6a33cdSVadim Pasternak if (err) { 1692c6a33cdSVadim Pasternak dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query fan\n"); 1702c6a33cdSVadim Pasternak return err; 1712c6a33cdSVadim Pasternak } 1722c6a33cdSVadim Pasternak mlxsw_reg_fore_unpack(fore_pl, mlwsw_hwmon_attr->type_index, &fault); 1732c6a33cdSVadim Pasternak 1742c6a33cdSVadim Pasternak return sprintf(buf, "%u\n", fault); 1752c6a33cdSVadim Pasternak } 1762c6a33cdSVadim Pasternak 17752581961SJiri Pirko static ssize_t mlxsw_hwmon_pwm_show(struct device *dev, 17852581961SJiri Pirko struct device_attribute *attr, 17952581961SJiri Pirko char *buf) 18052581961SJiri Pirko { 18152581961SJiri Pirko struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = 18252581961SJiri Pirko container_of(attr, struct mlxsw_hwmon_attr, dev_attr); 18352581961SJiri Pirko struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; 18452581961SJiri Pirko char mfsc_pl[MLXSW_REG_MFSC_LEN]; 18552581961SJiri Pirko int err; 18652581961SJiri Pirko 18752581961SJiri Pirko mlxsw_reg_mfsc_pack(mfsc_pl, mlwsw_hwmon_attr->type_index, 0); 18852581961SJiri Pirko err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mfsc), mfsc_pl); 18952581961SJiri Pirko if (err) { 19052581961SJiri Pirko dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query PWM\n"); 19152581961SJiri Pirko return err; 19252581961SJiri Pirko } 19352581961SJiri Pirko return sprintf(buf, "%u\n", 19452581961SJiri Pirko mlxsw_reg_mfsc_pwm_duty_cycle_get(mfsc_pl)); 19552581961SJiri Pirko } 19652581961SJiri Pirko 19752581961SJiri Pirko static ssize_t mlxsw_hwmon_pwm_store(struct device *dev, 19852581961SJiri Pirko struct device_attribute *attr, 19952581961SJiri Pirko const char *buf, size_t len) 20052581961SJiri Pirko { 20152581961SJiri Pirko struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = 20252581961SJiri Pirko container_of(attr, struct mlxsw_hwmon_attr, dev_attr); 20352581961SJiri Pirko struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; 20452581961SJiri Pirko char mfsc_pl[MLXSW_REG_MFSC_LEN]; 20552581961SJiri Pirko unsigned long val; 20652581961SJiri Pirko int err; 20752581961SJiri Pirko 20852581961SJiri Pirko err = kstrtoul(buf, 10, &val); 20952581961SJiri Pirko if (err) 21052581961SJiri Pirko return err; 21152581961SJiri Pirko if (val > 255) 21252581961SJiri Pirko return -EINVAL; 21352581961SJiri Pirko 21452581961SJiri Pirko mlxsw_reg_mfsc_pack(mfsc_pl, mlwsw_hwmon_attr->type_index, val); 21552581961SJiri Pirko err = mlxsw_reg_write(mlxsw_hwmon->core, MLXSW_REG(mfsc), mfsc_pl); 21652581961SJiri Pirko if (err) { 21752581961SJiri Pirko dev_err(mlxsw_hwmon->bus_info->dev, "Failed to write PWM\n"); 21852581961SJiri Pirko return err; 21952581961SJiri Pirko } 220515123e2SDan Carpenter return len; 22152581961SJiri Pirko } 22252581961SJiri Pirko 223ad38d47bSAmit Cohen static int mlxsw_hwmon_module_temp_get(struct device *dev, 2245c42eaa0SVadim Pasternak struct device_attribute *attr, 225ad38d47bSAmit Cohen int *p_temp) 2265c42eaa0SVadim Pasternak { 2275c42eaa0SVadim Pasternak struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = 2285c42eaa0SVadim Pasternak container_of(attr, struct mlxsw_hwmon_attr, dev_attr); 2295c42eaa0SVadim Pasternak struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; 230e4e93d6dSVadim Pasternak char mtmp_pl[MLXSW_REG_MTMP_LEN]; 2315c42eaa0SVadim Pasternak u8 module; 2325c42eaa0SVadim Pasternak int err; 2335c42eaa0SVadim Pasternak 2345c42eaa0SVadim Pasternak module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; 235e4e93d6dSVadim Pasternak mlxsw_reg_mtmp_pack(mtmp_pl, MLXSW_REG_MTMP_MODULE_INDEX_MIN + module, 236e4e93d6dSVadim Pasternak false, false); 237e4e93d6dSVadim Pasternak err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); 238ad38d47bSAmit Cohen if (err) { 239ad38d47bSAmit Cohen dev_err(dev, "Failed to query module temperature\n"); 240ad38d47bSAmit Cohen return err; 241ad38d47bSAmit Cohen } 242*314dbb19SMykola Kostenok mlxsw_reg_mtmp_unpack(mtmp_pl, p_temp, NULL, NULL, NULL, NULL); 243ad38d47bSAmit Cohen 244ad38d47bSAmit Cohen return 0; 245ad38d47bSAmit Cohen } 246ad38d47bSAmit Cohen 247ad38d47bSAmit Cohen static ssize_t mlxsw_hwmon_module_temp_show(struct device *dev, 248ad38d47bSAmit Cohen struct device_attribute *attr, 249ad38d47bSAmit Cohen char *buf) 250ad38d47bSAmit Cohen { 251ad38d47bSAmit Cohen int err, temp; 252ad38d47bSAmit Cohen 253ad38d47bSAmit Cohen err = mlxsw_hwmon_module_temp_get(dev, attr, &temp); 254e4e93d6dSVadim Pasternak if (err) 2555c42eaa0SVadim Pasternak return err; 2565c42eaa0SVadim Pasternak 257f485cc36SVadim Pasternak return sprintf(buf, "%d\n", temp); 2585c42eaa0SVadim Pasternak } 2595c42eaa0SVadim Pasternak 2605c42eaa0SVadim Pasternak static ssize_t mlxsw_hwmon_module_temp_fault_show(struct device *dev, 2615c42eaa0SVadim Pasternak struct device_attribute *attr, 2625c42eaa0SVadim Pasternak char *buf) 2635c42eaa0SVadim Pasternak { 2645c42eaa0SVadim Pasternak struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = 2655c42eaa0SVadim Pasternak container_of(attr, struct mlxsw_hwmon_attr, dev_attr); 2665c42eaa0SVadim Pasternak struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; 2675c42eaa0SVadim Pasternak char mtbr_pl[MLXSW_REG_MTBR_LEN] = {0}; 2685c42eaa0SVadim Pasternak u8 module, fault; 2695c42eaa0SVadim Pasternak u16 temp; 2705c42eaa0SVadim Pasternak int err; 2715c42eaa0SVadim Pasternak 2725c42eaa0SVadim Pasternak module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; 2735c42eaa0SVadim Pasternak mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, 2745c42eaa0SVadim Pasternak 1); 2755c42eaa0SVadim Pasternak err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtbr), mtbr_pl); 2765c42eaa0SVadim Pasternak if (err) { 27759e6158aSColin Ian King dev_err(dev, "Failed to query module temperature sensor\n"); 2785c42eaa0SVadim Pasternak return err; 2795c42eaa0SVadim Pasternak } 2805c42eaa0SVadim Pasternak 2815c42eaa0SVadim Pasternak mlxsw_reg_mtbr_temp_unpack(mtbr_pl, 0, &temp, NULL); 2825c42eaa0SVadim Pasternak 2835c42eaa0SVadim Pasternak /* Update status and temperature cache. */ 2845c42eaa0SVadim Pasternak switch (temp) { 2855c42eaa0SVadim Pasternak case MLXSW_REG_MTBR_BAD_SENS_INFO: 2865c42eaa0SVadim Pasternak /* Untrusted cable is connected. Reading temperature from its 2875c42eaa0SVadim Pasternak * sensor is faulty. 2885c42eaa0SVadim Pasternak */ 2895c42eaa0SVadim Pasternak fault = 1; 2905c42eaa0SVadim Pasternak break; 291df561f66SGustavo A. R. Silva case MLXSW_REG_MTBR_NO_CONN: 292df561f66SGustavo A. R. Silva case MLXSW_REG_MTBR_NO_TEMP_SENS: 2935c42eaa0SVadim Pasternak case MLXSW_REG_MTBR_INDEX_NA: 2945c42eaa0SVadim Pasternak default: 2955c42eaa0SVadim Pasternak fault = 0; 2965c42eaa0SVadim Pasternak break; 2975c42eaa0SVadim Pasternak } 2985c42eaa0SVadim Pasternak 2995c42eaa0SVadim Pasternak return sprintf(buf, "%u\n", fault); 3005c42eaa0SVadim Pasternak } 3015c42eaa0SVadim Pasternak 302ad38d47bSAmit Cohen static int mlxsw_hwmon_module_temp_critical_get(struct device *dev, 303ad38d47bSAmit Cohen struct device_attribute *attr, 304ad38d47bSAmit Cohen int *p_temp) 3055c42eaa0SVadim Pasternak { 3065c42eaa0SVadim Pasternak struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = 3075c42eaa0SVadim Pasternak container_of(attr, struct mlxsw_hwmon_attr, dev_attr); 3085c42eaa0SVadim Pasternak struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; 3095c42eaa0SVadim Pasternak u8 module; 3105c42eaa0SVadim Pasternak int err; 3115c42eaa0SVadim Pasternak 3125c42eaa0SVadim Pasternak module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; 3135c42eaa0SVadim Pasternak err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, module, 314ad38d47bSAmit Cohen SFP_TEMP_HIGH_WARN, p_temp); 3155c42eaa0SVadim Pasternak if (err) { 31659e6158aSColin Ian King dev_err(dev, "Failed to query module temperature thresholds\n"); 3175c42eaa0SVadim Pasternak return err; 3185c42eaa0SVadim Pasternak } 3195c42eaa0SVadim Pasternak 320ad38d47bSAmit Cohen return 0; 321ad38d47bSAmit Cohen } 322ad38d47bSAmit Cohen 323ad38d47bSAmit Cohen static ssize_t 324ad38d47bSAmit Cohen mlxsw_hwmon_module_temp_critical_show(struct device *dev, 325ad38d47bSAmit Cohen struct device_attribute *attr, char *buf) 326ad38d47bSAmit Cohen { 327ad38d47bSAmit Cohen int err, temp; 328ad38d47bSAmit Cohen 329ad38d47bSAmit Cohen err = mlxsw_hwmon_module_temp_critical_get(dev, attr, &temp); 330ad38d47bSAmit Cohen if (err) 331ad38d47bSAmit Cohen return err; 332ad38d47bSAmit Cohen 3335c42eaa0SVadim Pasternak return sprintf(buf, "%u\n", temp); 3345c42eaa0SVadim Pasternak } 3355c42eaa0SVadim Pasternak 336ad38d47bSAmit Cohen static int mlxsw_hwmon_module_temp_emergency_get(struct device *dev, 337ad38d47bSAmit Cohen struct device_attribute *attr, 338ad38d47bSAmit Cohen int *p_temp) 339ad38d47bSAmit Cohen { 340ad38d47bSAmit Cohen struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = 341ad38d47bSAmit Cohen container_of(attr, struct mlxsw_hwmon_attr, dev_attr); 342ad38d47bSAmit Cohen struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; 343ad38d47bSAmit Cohen u8 module; 344ad38d47bSAmit Cohen int err; 345ad38d47bSAmit Cohen 346ad38d47bSAmit Cohen module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; 347ad38d47bSAmit Cohen err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, module, 348ad38d47bSAmit Cohen SFP_TEMP_HIGH_ALARM, p_temp); 349ad38d47bSAmit Cohen if (err) { 350ad38d47bSAmit Cohen dev_err(dev, "Failed to query module temperature thresholds\n"); 351ad38d47bSAmit Cohen return err; 352ad38d47bSAmit Cohen } 353ad38d47bSAmit Cohen 354ad38d47bSAmit Cohen return 0; 355ad38d47bSAmit Cohen } 356ad38d47bSAmit Cohen 3575c42eaa0SVadim Pasternak static ssize_t 3585c42eaa0SVadim Pasternak mlxsw_hwmon_module_temp_emergency_show(struct device *dev, 3595c42eaa0SVadim Pasternak struct device_attribute *attr, 3605c42eaa0SVadim Pasternak char *buf) 3615c42eaa0SVadim Pasternak { 362ad38d47bSAmit Cohen int err, temp; 3635c42eaa0SVadim Pasternak 364ad38d47bSAmit Cohen err = mlxsw_hwmon_module_temp_emergency_get(dev, attr, &temp); 365ad38d47bSAmit Cohen if (err) 3665c42eaa0SVadim Pasternak return err; 3675c42eaa0SVadim Pasternak 3685c42eaa0SVadim Pasternak return sprintf(buf, "%u\n", temp); 3695c42eaa0SVadim Pasternak } 3705c42eaa0SVadim Pasternak 371a53779deSVadim Pasternak static ssize_t 372a53779deSVadim Pasternak mlxsw_hwmon_module_temp_label_show(struct device *dev, 373a53779deSVadim Pasternak struct device_attribute *attr, 374a53779deSVadim Pasternak char *buf) 375a53779deSVadim Pasternak { 376a53779deSVadim Pasternak struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = 377a53779deSVadim Pasternak container_of(attr, struct mlxsw_hwmon_attr, dev_attr); 378a53779deSVadim Pasternak 379a53779deSVadim Pasternak return sprintf(buf, "front panel %03u\n", 380a53779deSVadim Pasternak mlwsw_hwmon_attr->type_index); 381a53779deSVadim Pasternak } 382a53779deSVadim Pasternak 3832e265a8bSVadim Pasternak static ssize_t 3842e265a8bSVadim Pasternak mlxsw_hwmon_gbox_temp_label_show(struct device *dev, 3852e265a8bSVadim Pasternak struct device_attribute *attr, 3862e265a8bSVadim Pasternak char *buf) 3872e265a8bSVadim Pasternak { 3882e265a8bSVadim Pasternak struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = 3892e265a8bSVadim Pasternak container_of(attr, struct mlxsw_hwmon_attr, dev_attr); 3902e265a8bSVadim Pasternak struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; 3912e265a8bSVadim Pasternak int index = mlwsw_hwmon_attr->type_index - 392ea30a92aSVadim Pasternak mlxsw_hwmon->module_sensor_max + 1; 3932e265a8bSVadim Pasternak 3942e265a8bSVadim Pasternak return sprintf(buf, "gearbox %03u\n", index); 3952e265a8bSVadim Pasternak } 3962e265a8bSVadim Pasternak 39791df5d3aSAmit Cohen static ssize_t mlxsw_hwmon_temp_critical_alarm_show(struct device *dev, 39891df5d3aSAmit Cohen struct device_attribute *attr, 39991df5d3aSAmit Cohen char *buf) 40091df5d3aSAmit Cohen { 40191df5d3aSAmit Cohen int err, temp, emergency_temp, critic_temp; 40291df5d3aSAmit Cohen 40391df5d3aSAmit Cohen err = mlxsw_hwmon_module_temp_get(dev, attr, &temp); 40491df5d3aSAmit Cohen if (err) 40591df5d3aSAmit Cohen return err; 40691df5d3aSAmit Cohen 40791df5d3aSAmit Cohen if (temp <= 0) 40891df5d3aSAmit Cohen return sprintf(buf, "%d\n", false); 40991df5d3aSAmit Cohen 41091df5d3aSAmit Cohen err = mlxsw_hwmon_module_temp_emergency_get(dev, attr, &emergency_temp); 41191df5d3aSAmit Cohen if (err) 41291df5d3aSAmit Cohen return err; 41391df5d3aSAmit Cohen 41491df5d3aSAmit Cohen if (temp >= emergency_temp) 41591df5d3aSAmit Cohen return sprintf(buf, "%d\n", false); 41691df5d3aSAmit Cohen 41791df5d3aSAmit Cohen err = mlxsw_hwmon_module_temp_critical_get(dev, attr, &critic_temp); 41891df5d3aSAmit Cohen if (err) 41991df5d3aSAmit Cohen return err; 42091df5d3aSAmit Cohen 42191df5d3aSAmit Cohen return sprintf(buf, "%d\n", temp >= critic_temp); 42291df5d3aSAmit Cohen } 42391df5d3aSAmit Cohen 42491df5d3aSAmit Cohen static ssize_t mlxsw_hwmon_temp_emergency_alarm_show(struct device *dev, 42591df5d3aSAmit Cohen struct device_attribute *attr, 42691df5d3aSAmit Cohen char *buf) 42791df5d3aSAmit Cohen { 42891df5d3aSAmit Cohen int err, temp, emergency_temp; 42991df5d3aSAmit Cohen 43091df5d3aSAmit Cohen err = mlxsw_hwmon_module_temp_get(dev, attr, &temp); 43191df5d3aSAmit Cohen if (err) 43291df5d3aSAmit Cohen return err; 43391df5d3aSAmit Cohen 43491df5d3aSAmit Cohen if (temp <= 0) 43591df5d3aSAmit Cohen return sprintf(buf, "%d\n", false); 43691df5d3aSAmit Cohen 43791df5d3aSAmit Cohen err = mlxsw_hwmon_module_temp_emergency_get(dev, attr, &emergency_temp); 43891df5d3aSAmit Cohen if (err) 43991df5d3aSAmit Cohen return err; 44091df5d3aSAmit Cohen 44191df5d3aSAmit Cohen return sprintf(buf, "%d\n", temp >= emergency_temp); 44291df5d3aSAmit Cohen } 44391df5d3aSAmit Cohen 44489309da3SJiri Pirko enum mlxsw_hwmon_attr_type { 44589309da3SJiri Pirko MLXSW_HWMON_ATTR_TYPE_TEMP, 44689309da3SJiri Pirko MLXSW_HWMON_ATTR_TYPE_TEMP_MAX, 447e7bc73cbSJiri Pirko MLXSW_HWMON_ATTR_TYPE_TEMP_RST, 44852581961SJiri Pirko MLXSW_HWMON_ATTR_TYPE_FAN_RPM, 4492c6a33cdSVadim Pasternak MLXSW_HWMON_ATTR_TYPE_FAN_FAULT, 45052581961SJiri Pirko MLXSW_HWMON_ATTR_TYPE_PWM, 4515c42eaa0SVadim Pasternak MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE, 4525c42eaa0SVadim Pasternak MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_FAULT, 4535c42eaa0SVadim Pasternak MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_CRIT, 4545c42eaa0SVadim Pasternak MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_EMERG, 455a53779deSVadim Pasternak MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_LABEL, 4562e265a8bSVadim Pasternak MLXSW_HWMON_ATTR_TYPE_TEMP_GBOX_LABEL, 45791df5d3aSAmit Cohen MLXSW_HWMON_ATTR_TYPE_TEMP_CRIT_ALARM, 45891df5d3aSAmit Cohen MLXSW_HWMON_ATTR_TYPE_TEMP_EMERGENCY_ALARM, 45989309da3SJiri Pirko }; 46089309da3SJiri Pirko 46189309da3SJiri Pirko static void mlxsw_hwmon_attr_add(struct mlxsw_hwmon *mlxsw_hwmon, 46289309da3SJiri Pirko enum mlxsw_hwmon_attr_type attr_type, 46389309da3SJiri Pirko unsigned int type_index, unsigned int num) { 46489309da3SJiri Pirko struct mlxsw_hwmon_attr *mlxsw_hwmon_attr; 46589309da3SJiri Pirko unsigned int attr_index; 46689309da3SJiri Pirko 46789309da3SJiri Pirko attr_index = mlxsw_hwmon->attrs_count; 46889309da3SJiri Pirko mlxsw_hwmon_attr = &mlxsw_hwmon->hwmon_attrs[attr_index]; 46989309da3SJiri Pirko 47089309da3SJiri Pirko switch (attr_type) { 47189309da3SJiri Pirko case MLXSW_HWMON_ATTR_TYPE_TEMP: 47289309da3SJiri Pirko mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_temp_show; 473d3757ba4SJoe Perches mlxsw_hwmon_attr->dev_attr.attr.mode = 0444; 47489309da3SJiri Pirko snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), 47589309da3SJiri Pirko "temp%u_input", num + 1); 47689309da3SJiri Pirko break; 47789309da3SJiri Pirko case MLXSW_HWMON_ATTR_TYPE_TEMP_MAX: 47889309da3SJiri Pirko mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_temp_max_show; 479d3757ba4SJoe Perches mlxsw_hwmon_attr->dev_attr.attr.mode = 0444; 48089309da3SJiri Pirko snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), 48189309da3SJiri Pirko "temp%u_highest", num + 1); 48289309da3SJiri Pirko break; 483e7bc73cbSJiri Pirko case MLXSW_HWMON_ATTR_TYPE_TEMP_RST: 484e7bc73cbSJiri Pirko mlxsw_hwmon_attr->dev_attr.store = mlxsw_hwmon_temp_rst_store; 485d3757ba4SJoe Perches mlxsw_hwmon_attr->dev_attr.attr.mode = 0200; 486e7bc73cbSJiri Pirko snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), 487e7bc73cbSJiri Pirko "temp%u_reset_history", num + 1); 488e7bc73cbSJiri Pirko break; 48952581961SJiri Pirko case MLXSW_HWMON_ATTR_TYPE_FAN_RPM: 49052581961SJiri Pirko mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_fan_rpm_show; 491d3757ba4SJoe Perches mlxsw_hwmon_attr->dev_attr.attr.mode = 0444; 49252581961SJiri Pirko snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), 49352581961SJiri Pirko "fan%u_input", num + 1); 49452581961SJiri Pirko break; 4952c6a33cdSVadim Pasternak case MLXSW_HWMON_ATTR_TYPE_FAN_FAULT: 4962c6a33cdSVadim Pasternak mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_fan_fault_show; 4972c6a33cdSVadim Pasternak mlxsw_hwmon_attr->dev_attr.attr.mode = 0444; 4982c6a33cdSVadim Pasternak snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), 4992c6a33cdSVadim Pasternak "fan%u_fault", num + 1); 5002c6a33cdSVadim Pasternak break; 50152581961SJiri Pirko case MLXSW_HWMON_ATTR_TYPE_PWM: 50252581961SJiri Pirko mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_pwm_show; 50352581961SJiri Pirko mlxsw_hwmon_attr->dev_attr.store = mlxsw_hwmon_pwm_store; 504d3757ba4SJoe Perches mlxsw_hwmon_attr->dev_attr.attr.mode = 0644; 50552581961SJiri Pirko snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), 50652581961SJiri Pirko "pwm%u", num + 1); 50752581961SJiri Pirko break; 5085c42eaa0SVadim Pasternak case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE: 5095c42eaa0SVadim Pasternak mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_module_temp_show; 5105c42eaa0SVadim Pasternak mlxsw_hwmon_attr->dev_attr.attr.mode = 0444; 5115c42eaa0SVadim Pasternak snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), 5125c42eaa0SVadim Pasternak "temp%u_input", num + 1); 5135c42eaa0SVadim Pasternak break; 5145c42eaa0SVadim Pasternak case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_FAULT: 5155c42eaa0SVadim Pasternak mlxsw_hwmon_attr->dev_attr.show = 5165c42eaa0SVadim Pasternak mlxsw_hwmon_module_temp_fault_show; 5175c42eaa0SVadim Pasternak mlxsw_hwmon_attr->dev_attr.attr.mode = 0444; 5185c42eaa0SVadim Pasternak snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), 5195c42eaa0SVadim Pasternak "temp%u_fault", num + 1); 5205c42eaa0SVadim Pasternak break; 5215c42eaa0SVadim Pasternak case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_CRIT: 5225c42eaa0SVadim Pasternak mlxsw_hwmon_attr->dev_attr.show = 5235c42eaa0SVadim Pasternak mlxsw_hwmon_module_temp_critical_show; 5245c42eaa0SVadim Pasternak mlxsw_hwmon_attr->dev_attr.attr.mode = 0444; 5255c42eaa0SVadim Pasternak snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), 5265c42eaa0SVadim Pasternak "temp%u_crit", num + 1); 5275c42eaa0SVadim Pasternak break; 5285c42eaa0SVadim Pasternak case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_EMERG: 5295c42eaa0SVadim Pasternak mlxsw_hwmon_attr->dev_attr.show = 5305c42eaa0SVadim Pasternak mlxsw_hwmon_module_temp_emergency_show; 5315c42eaa0SVadim Pasternak mlxsw_hwmon_attr->dev_attr.attr.mode = 0444; 5325c42eaa0SVadim Pasternak snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), 5335c42eaa0SVadim Pasternak "temp%u_emergency", num + 1); 5345c42eaa0SVadim Pasternak break; 535a53779deSVadim Pasternak case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_LABEL: 536a53779deSVadim Pasternak mlxsw_hwmon_attr->dev_attr.show = 537a53779deSVadim Pasternak mlxsw_hwmon_module_temp_label_show; 538a53779deSVadim Pasternak mlxsw_hwmon_attr->dev_attr.attr.mode = 0444; 539a53779deSVadim Pasternak snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), 540a53779deSVadim Pasternak "temp%u_label", num + 1); 541a53779deSVadim Pasternak break; 5422e265a8bSVadim Pasternak case MLXSW_HWMON_ATTR_TYPE_TEMP_GBOX_LABEL: 5432e265a8bSVadim Pasternak mlxsw_hwmon_attr->dev_attr.show = 5442e265a8bSVadim Pasternak mlxsw_hwmon_gbox_temp_label_show; 5452e265a8bSVadim Pasternak mlxsw_hwmon_attr->dev_attr.attr.mode = 0444; 5462e265a8bSVadim Pasternak snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), 5472e265a8bSVadim Pasternak "temp%u_label", num + 1); 5482e265a8bSVadim Pasternak break; 54991df5d3aSAmit Cohen case MLXSW_HWMON_ATTR_TYPE_TEMP_CRIT_ALARM: 55091df5d3aSAmit Cohen mlxsw_hwmon_attr->dev_attr.show = 55191df5d3aSAmit Cohen mlxsw_hwmon_temp_critical_alarm_show; 55291df5d3aSAmit Cohen mlxsw_hwmon_attr->dev_attr.attr.mode = 0444; 55391df5d3aSAmit Cohen snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), 55491df5d3aSAmit Cohen "temp%u_crit_alarm", num + 1); 55591df5d3aSAmit Cohen break; 55691df5d3aSAmit Cohen case MLXSW_HWMON_ATTR_TYPE_TEMP_EMERGENCY_ALARM: 55791df5d3aSAmit Cohen mlxsw_hwmon_attr->dev_attr.show = 55891df5d3aSAmit Cohen mlxsw_hwmon_temp_emergency_alarm_show; 55991df5d3aSAmit Cohen mlxsw_hwmon_attr->dev_attr.attr.mode = 0444; 56091df5d3aSAmit Cohen snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), 56191df5d3aSAmit Cohen "temp%u_emergency_alarm", num + 1); 56291df5d3aSAmit Cohen break; 56389309da3SJiri Pirko default: 5646b20da4dSJiri Pirko WARN_ON(1); 56589309da3SJiri Pirko } 56689309da3SJiri Pirko 56789309da3SJiri Pirko mlxsw_hwmon_attr->type_index = type_index; 56889309da3SJiri Pirko mlxsw_hwmon_attr->hwmon = mlxsw_hwmon; 56989309da3SJiri Pirko mlxsw_hwmon_attr->dev_attr.attr.name = mlxsw_hwmon_attr->name; 57089309da3SJiri Pirko sysfs_attr_init(&mlxsw_hwmon_attr->dev_attr.attr); 57189309da3SJiri Pirko 57289309da3SJiri Pirko mlxsw_hwmon->attrs[attr_index] = &mlxsw_hwmon_attr->dev_attr.attr; 57389309da3SJiri Pirko mlxsw_hwmon->attrs_count++; 57489309da3SJiri Pirko } 57589309da3SJiri Pirko 57689309da3SJiri Pirko static int mlxsw_hwmon_temp_init(struct mlxsw_hwmon *mlxsw_hwmon) 57789309da3SJiri Pirko { 5785b090740SElad Raz char mtcap_pl[MLXSW_REG_MTCAP_LEN] = {0}; 57989309da3SJiri Pirko int i; 58089309da3SJiri Pirko int err; 58189309da3SJiri Pirko 58289309da3SJiri Pirko err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtcap), mtcap_pl); 58389309da3SJiri Pirko if (err) { 58489309da3SJiri Pirko dev_err(mlxsw_hwmon->bus_info->dev, "Failed to get number of temp sensors\n"); 58589309da3SJiri Pirko return err; 58689309da3SJiri Pirko } 5875c42eaa0SVadim Pasternak mlxsw_hwmon->sensor_count = mlxsw_reg_mtcap_sensor_count_get(mtcap_pl); 5885c42eaa0SVadim Pasternak for (i = 0; i < mlxsw_hwmon->sensor_count; i++) { 589fb1292f8SAmit Cohen char mtmp_pl[MLXSW_REG_MTMP_LEN] = {0}; 590fb1292f8SAmit Cohen 591fb1292f8SAmit Cohen mlxsw_reg_mtmp_sensor_index_set(mtmp_pl, i); 592fb1292f8SAmit Cohen err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), 593fb1292f8SAmit Cohen mtmp_pl); 594fb1292f8SAmit Cohen if (err) 595fb1292f8SAmit Cohen return err; 596fb1292f8SAmit Cohen mlxsw_reg_mtmp_mte_set(mtmp_pl, true); 597fb1292f8SAmit Cohen mlxsw_reg_mtmp_mtr_set(mtmp_pl, true); 59889309da3SJiri Pirko err = mlxsw_reg_write(mlxsw_hwmon->core, 59989309da3SJiri Pirko MLXSW_REG(mtmp), mtmp_pl); 60089309da3SJiri Pirko if (err) { 60189309da3SJiri Pirko dev_err(mlxsw_hwmon->bus_info->dev, "Failed to setup temp sensor number %d\n", 60289309da3SJiri Pirko i); 60389309da3SJiri Pirko return err; 60489309da3SJiri Pirko } 60589309da3SJiri Pirko mlxsw_hwmon_attr_add(mlxsw_hwmon, 60689309da3SJiri Pirko MLXSW_HWMON_ATTR_TYPE_TEMP, i, i); 60789309da3SJiri Pirko mlxsw_hwmon_attr_add(mlxsw_hwmon, 60889309da3SJiri Pirko MLXSW_HWMON_ATTR_TYPE_TEMP_MAX, i, i); 609e7bc73cbSJiri Pirko mlxsw_hwmon_attr_add(mlxsw_hwmon, 610e7bc73cbSJiri Pirko MLXSW_HWMON_ATTR_TYPE_TEMP_RST, i, i); 61189309da3SJiri Pirko } 61289309da3SJiri Pirko return 0; 61389309da3SJiri Pirko } 61489309da3SJiri Pirko 61552581961SJiri Pirko static int mlxsw_hwmon_fans_init(struct mlxsw_hwmon *mlxsw_hwmon) 61652581961SJiri Pirko { 6175b090740SElad Raz char mfcr_pl[MLXSW_REG_MFCR_LEN] = {0}; 61852581961SJiri Pirko enum mlxsw_reg_mfcr_pwm_frequency freq; 61952581961SJiri Pirko unsigned int type_index; 62052581961SJiri Pirko unsigned int num; 62152581961SJiri Pirko u16 tacho_active; 62252581961SJiri Pirko u8 pwm_active; 62352581961SJiri Pirko int err; 62452581961SJiri Pirko 62552581961SJiri Pirko err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mfcr), mfcr_pl); 62652581961SJiri Pirko if (err) { 62752581961SJiri Pirko dev_err(mlxsw_hwmon->bus_info->dev, "Failed to get to probe PWMs and Tachometers\n"); 62852581961SJiri Pirko return err; 62952581961SJiri Pirko } 63052581961SJiri Pirko mlxsw_reg_mfcr_unpack(mfcr_pl, &freq, &tacho_active, &pwm_active); 63152581961SJiri Pirko num = 0; 63252581961SJiri Pirko for (type_index = 0; type_index < MLXSW_MFCR_TACHOS_MAX; type_index++) { 6332c6a33cdSVadim Pasternak if (tacho_active & BIT(type_index)) { 63452581961SJiri Pirko mlxsw_hwmon_attr_add(mlxsw_hwmon, 63552581961SJiri Pirko MLXSW_HWMON_ATTR_TYPE_FAN_RPM, 6362c6a33cdSVadim Pasternak type_index, num); 6372c6a33cdSVadim Pasternak mlxsw_hwmon_attr_add(mlxsw_hwmon, 6382c6a33cdSVadim Pasternak MLXSW_HWMON_ATTR_TYPE_FAN_FAULT, 63952581961SJiri Pirko type_index, num++); 64052581961SJiri Pirko } 6412c6a33cdSVadim Pasternak } 64252581961SJiri Pirko num = 0; 64352581961SJiri Pirko for (type_index = 0; type_index < MLXSW_MFCR_PWMS_MAX; type_index++) { 64452581961SJiri Pirko if (pwm_active & BIT(type_index)) 64552581961SJiri Pirko mlxsw_hwmon_attr_add(mlxsw_hwmon, 64652581961SJiri Pirko MLXSW_HWMON_ATTR_TYPE_PWM, 64752581961SJiri Pirko type_index, num++); 64852581961SJiri Pirko } 64952581961SJiri Pirko return 0; 65052581961SJiri Pirko } 65152581961SJiri Pirko 6525c42eaa0SVadim Pasternak static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon) 6535c42eaa0SVadim Pasternak { 654ea30a92aSVadim Pasternak char mgpir_pl[MLXSW_REG_MGPIR_LEN]; 655ea30a92aSVadim Pasternak u8 module_sensor_max; 656ea30a92aSVadim Pasternak int i, err; 6575c42eaa0SVadim Pasternak 658c52ecff7SVadim Pasternak if (!mlxsw_core_res_query_enabled(mlxsw_hwmon->core)) 659c52ecff7SVadim Pasternak return 0; 660c52ecff7SVadim Pasternak 661ea30a92aSVadim Pasternak mlxsw_reg_mgpir_pack(mgpir_pl); 662ea30a92aSVadim Pasternak err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mgpir), mgpir_pl); 663ea30a92aSVadim Pasternak if (err) 664ea30a92aSVadim Pasternak return err; 665ea30a92aSVadim Pasternak 666ea30a92aSVadim Pasternak mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, 667ea30a92aSVadim Pasternak &module_sensor_max); 668ea30a92aSVadim Pasternak 6695c42eaa0SVadim Pasternak /* Add extra attributes for module temperature. Sensor index is 6705c42eaa0SVadim Pasternak * assigned to sensor_count value, while all indexed before 6715c42eaa0SVadim Pasternak * sensor_count are already utilized by the sensors connected through 6725c42eaa0SVadim Pasternak * mtmp register by mlxsw_hwmon_temp_init(). 6735c42eaa0SVadim Pasternak */ 674ea30a92aSVadim Pasternak mlxsw_hwmon->module_sensor_max = mlxsw_hwmon->sensor_count + 675ea30a92aSVadim Pasternak module_sensor_max; 676ea30a92aSVadim Pasternak for (i = mlxsw_hwmon->sensor_count; 677ea30a92aSVadim Pasternak i < mlxsw_hwmon->module_sensor_max; i++) { 6785c42eaa0SVadim Pasternak mlxsw_hwmon_attr_add(mlxsw_hwmon, 679ea30a92aSVadim Pasternak MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE, i, i); 6805c42eaa0SVadim Pasternak mlxsw_hwmon_attr_add(mlxsw_hwmon, 6815c42eaa0SVadim Pasternak MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_FAULT, 682ea30a92aSVadim Pasternak i, i); 6835c42eaa0SVadim Pasternak mlxsw_hwmon_attr_add(mlxsw_hwmon, 684ea30a92aSVadim Pasternak MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_CRIT, i, 685ea30a92aSVadim Pasternak i); 6865c42eaa0SVadim Pasternak mlxsw_hwmon_attr_add(mlxsw_hwmon, 6875c42eaa0SVadim Pasternak MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_EMERG, 688ea30a92aSVadim Pasternak i, i); 689a53779deSVadim Pasternak mlxsw_hwmon_attr_add(mlxsw_hwmon, 690a53779deSVadim Pasternak MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_LABEL, 691ea30a92aSVadim Pasternak i, i); 69291df5d3aSAmit Cohen mlxsw_hwmon_attr_add(mlxsw_hwmon, 69391df5d3aSAmit Cohen MLXSW_HWMON_ATTR_TYPE_TEMP_CRIT_ALARM, 69491df5d3aSAmit Cohen i, i); 69591df5d3aSAmit Cohen mlxsw_hwmon_attr_add(mlxsw_hwmon, 69691df5d3aSAmit Cohen MLXSW_HWMON_ATTR_TYPE_TEMP_EMERGENCY_ALARM, 69791df5d3aSAmit Cohen i, i); 6985c42eaa0SVadim Pasternak } 6992e265a8bSVadim Pasternak 7002e265a8bSVadim Pasternak return 0; 7012e265a8bSVadim Pasternak } 7022e265a8bSVadim Pasternak 7032e265a8bSVadim Pasternak static int mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon) 7042e265a8bSVadim Pasternak { 70536844c85SVadim Pasternak enum mlxsw_reg_mgpir_device_type device_type; 7062e265a8bSVadim Pasternak int index, max_index, sensor_index; 7072e265a8bSVadim Pasternak char mgpir_pl[MLXSW_REG_MGPIR_LEN]; 7082e265a8bSVadim Pasternak char mtmp_pl[MLXSW_REG_MTMP_LEN]; 7092e265a8bSVadim Pasternak u8 gbox_num; 7102e265a8bSVadim Pasternak int err; 7112e265a8bSVadim Pasternak 7122e265a8bSVadim Pasternak mlxsw_reg_mgpir_pack(mgpir_pl); 7132e265a8bSVadim Pasternak err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mgpir), mgpir_pl); 7142e265a8bSVadim Pasternak if (err) 7152e265a8bSVadim Pasternak return err; 7162e265a8bSVadim Pasternak 71736844c85SVadim Pasternak mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, &device_type, NULL, NULL); 71836844c85SVadim Pasternak if (device_type != MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE || 71936844c85SVadim Pasternak !gbox_num) 7202e265a8bSVadim Pasternak return 0; 7212e265a8bSVadim Pasternak 722ea30a92aSVadim Pasternak index = mlxsw_hwmon->module_sensor_max; 723ea30a92aSVadim Pasternak max_index = mlxsw_hwmon->module_sensor_max + gbox_num; 7242e265a8bSVadim Pasternak while (index < max_index) { 725ea30a92aSVadim Pasternak sensor_index = index % mlxsw_hwmon->module_sensor_max + 7262e265a8bSVadim Pasternak MLXSW_REG_MTMP_GBOX_INDEX_MIN; 7272e265a8bSVadim Pasternak mlxsw_reg_mtmp_pack(mtmp_pl, sensor_index, true, true); 7282e265a8bSVadim Pasternak err = mlxsw_reg_write(mlxsw_hwmon->core, 7292e265a8bSVadim Pasternak MLXSW_REG(mtmp), mtmp_pl); 7302e265a8bSVadim Pasternak if (err) { 7312e265a8bSVadim Pasternak dev_err(mlxsw_hwmon->bus_info->dev, "Failed to setup temp sensor number %d\n", 7322e265a8bSVadim Pasternak sensor_index); 7332e265a8bSVadim Pasternak return err; 7342e265a8bSVadim Pasternak } 7352e265a8bSVadim Pasternak mlxsw_hwmon_attr_add(mlxsw_hwmon, MLXSW_HWMON_ATTR_TYPE_TEMP, 7362e265a8bSVadim Pasternak index, index); 7372e265a8bSVadim Pasternak mlxsw_hwmon_attr_add(mlxsw_hwmon, 7382e265a8bSVadim Pasternak MLXSW_HWMON_ATTR_TYPE_TEMP_MAX, index, 7392e265a8bSVadim Pasternak index); 7402e265a8bSVadim Pasternak mlxsw_hwmon_attr_add(mlxsw_hwmon, 7412e265a8bSVadim Pasternak MLXSW_HWMON_ATTR_TYPE_TEMP_RST, index, 7422e265a8bSVadim Pasternak index); 7432e265a8bSVadim Pasternak mlxsw_hwmon_attr_add(mlxsw_hwmon, 7442e265a8bSVadim Pasternak MLXSW_HWMON_ATTR_TYPE_TEMP_GBOX_LABEL, 7452e265a8bSVadim Pasternak index, index); 7462e265a8bSVadim Pasternak index++; 7472e265a8bSVadim Pasternak } 7485c42eaa0SVadim Pasternak 7495c42eaa0SVadim Pasternak return 0; 7505c42eaa0SVadim Pasternak } 7515c42eaa0SVadim Pasternak 75289309da3SJiri Pirko int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core, 75389309da3SJiri Pirko const struct mlxsw_bus_info *mlxsw_bus_info, 75489309da3SJiri Pirko struct mlxsw_hwmon **p_hwmon) 75589309da3SJiri Pirko { 75689309da3SJiri Pirko struct mlxsw_hwmon *mlxsw_hwmon; 75789309da3SJiri Pirko struct device *hwmon_dev; 75889309da3SJiri Pirko int err; 75989309da3SJiri Pirko 7609b3bc7dbSIdo Schimmel mlxsw_hwmon = kzalloc(sizeof(*mlxsw_hwmon), GFP_KERNEL); 76189309da3SJiri Pirko if (!mlxsw_hwmon) 76289309da3SJiri Pirko return -ENOMEM; 76389309da3SJiri Pirko mlxsw_hwmon->core = mlxsw_core; 76489309da3SJiri Pirko mlxsw_hwmon->bus_info = mlxsw_bus_info; 76589309da3SJiri Pirko 76689309da3SJiri Pirko err = mlxsw_hwmon_temp_init(mlxsw_hwmon); 76789309da3SJiri Pirko if (err) 76889309da3SJiri Pirko goto err_temp_init; 76989309da3SJiri Pirko 77052581961SJiri Pirko err = mlxsw_hwmon_fans_init(mlxsw_hwmon); 77152581961SJiri Pirko if (err) 77252581961SJiri Pirko goto err_fans_init; 77352581961SJiri Pirko 7745c42eaa0SVadim Pasternak err = mlxsw_hwmon_module_init(mlxsw_hwmon); 7755c42eaa0SVadim Pasternak if (err) 7765c42eaa0SVadim Pasternak goto err_temp_module_init; 7775c42eaa0SVadim Pasternak 7782e265a8bSVadim Pasternak err = mlxsw_hwmon_gearbox_init(mlxsw_hwmon); 7792e265a8bSVadim Pasternak if (err) 7802e265a8bSVadim Pasternak goto err_temp_gearbox_init; 7812e265a8bSVadim Pasternak 78289309da3SJiri Pirko mlxsw_hwmon->groups[0] = &mlxsw_hwmon->group; 78389309da3SJiri Pirko mlxsw_hwmon->group.attrs = mlxsw_hwmon->attrs; 78489309da3SJiri Pirko 7859b3bc7dbSIdo Schimmel hwmon_dev = hwmon_device_register_with_groups(mlxsw_bus_info->dev, 7869b3bc7dbSIdo Schimmel "mlxsw", mlxsw_hwmon, 78789309da3SJiri Pirko mlxsw_hwmon->groups); 78889309da3SJiri Pirko if (IS_ERR(hwmon_dev)) { 78989309da3SJiri Pirko err = PTR_ERR(hwmon_dev); 79089309da3SJiri Pirko goto err_hwmon_register; 79189309da3SJiri Pirko } 79289309da3SJiri Pirko 79389309da3SJiri Pirko mlxsw_hwmon->hwmon_dev = hwmon_dev; 79489309da3SJiri Pirko *p_hwmon = mlxsw_hwmon; 79589309da3SJiri Pirko return 0; 79689309da3SJiri Pirko 79789309da3SJiri Pirko err_hwmon_register: 7982e265a8bSVadim Pasternak err_temp_gearbox_init: 7995c42eaa0SVadim Pasternak err_temp_module_init: 80052581961SJiri Pirko err_fans_init: 80189309da3SJiri Pirko err_temp_init: 8029b3bc7dbSIdo Schimmel kfree(mlxsw_hwmon); 80389309da3SJiri Pirko return err; 80489309da3SJiri Pirko } 8059b3bc7dbSIdo Schimmel 8069b3bc7dbSIdo Schimmel void mlxsw_hwmon_fini(struct mlxsw_hwmon *mlxsw_hwmon) 8079b3bc7dbSIdo Schimmel { 8089b3bc7dbSIdo Schimmel hwmon_device_unregister(mlxsw_hwmon->hwmon_dev); 8099b3bc7dbSIdo Schimmel kfree(mlxsw_hwmon); 8109b3bc7dbSIdo Schimmel } 811