cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

core_hwmon.c (28931B)


      1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
      2/* Copyright (c) 2015-2018 Mellanox Technologies. All rights reserved */
      3
      4#include <linux/kernel.h>
      5#include <linux/types.h>
      6#include <linux/device.h>
      7#include <linux/sysfs.h>
      8#include <linux/hwmon.h>
      9#include <linux/err.h>
     10#include <linux/sfp.h>
     11
     12#include "core.h"
     13#include "core_env.h"
     14
     15#define MLXSW_HWMON_SENSORS_MAX_COUNT 64
     16#define MLXSW_HWMON_MODULES_MAX_COUNT 64
     17#define MLXSW_HWMON_GEARBOXES_MAX_COUNT 32
     18
     19#define MLXSW_HWMON_ATTR_PER_SENSOR 3
     20#define MLXSW_HWMON_ATTR_PER_MODULE 7
     21#define MLXSW_HWMON_ATTR_PER_GEARBOX 4
     22#define MLXSW_HWMON_DEV_NAME_LEN_MAX 16
     23
     24#define MLXSW_HWMON_ATTR_COUNT (MLXSW_HWMON_SENSORS_MAX_COUNT * MLXSW_HWMON_ATTR_PER_SENSOR + \
     25				MLXSW_HWMON_MODULES_MAX_COUNT * MLXSW_HWMON_ATTR_PER_MODULE + \
     26				MLXSW_HWMON_GEARBOXES_MAX_COUNT * MLXSW_HWMON_ATTR_PER_GEARBOX + \
     27				MLXSW_MFCR_TACHOS_MAX + MLXSW_MFCR_PWMS_MAX)
     28
     29struct mlxsw_hwmon_attr {
     30	struct device_attribute dev_attr;
     31	struct mlxsw_hwmon_dev *mlxsw_hwmon_dev;
     32	unsigned int type_index;
     33	char name[32];
     34};
     35
     36static int mlxsw_hwmon_get_attr_index(int index, int count)
     37{
     38	if (index >= count)
     39		return index % count + MLXSW_REG_MTMP_GBOX_INDEX_MIN;
     40
     41	return index;
     42}
     43
     44struct mlxsw_hwmon_dev {
     45	char name[MLXSW_HWMON_DEV_NAME_LEN_MAX];
     46	struct mlxsw_hwmon *hwmon;
     47	struct device *hwmon_dev;
     48	struct attribute_group group;
     49	const struct attribute_group *groups[2];
     50	struct attribute *attrs[MLXSW_HWMON_ATTR_COUNT + 1];
     51	struct mlxsw_hwmon_attr hwmon_attrs[MLXSW_HWMON_ATTR_COUNT];
     52	unsigned int attrs_count;
     53	u8 sensor_count;
     54	u8 module_sensor_max;
     55	u8 slot_index;
     56	bool active;
     57};
     58
     59struct mlxsw_hwmon {
     60	struct mlxsw_core *core;
     61	const struct mlxsw_bus_info *bus_info;
     62	struct mlxsw_hwmon_dev line_cards[];
     63};
     64
     65static ssize_t mlxsw_hwmon_temp_show(struct device *dev,
     66				     struct device_attribute *attr,
     67				     char *buf)
     68{
     69	struct mlxsw_hwmon_attr *mlxsw_hwmon_attr =
     70			container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
     71	struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev;
     72	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon;
     73	char mtmp_pl[MLXSW_REG_MTMP_LEN];
     74	int temp, index;
     75	int err;
     76
     77	index = mlxsw_hwmon_get_attr_index(mlxsw_hwmon_attr->type_index,
     78					   mlxsw_hwmon_dev->module_sensor_max);
     79	mlxsw_reg_mtmp_pack(mtmp_pl, mlxsw_hwmon_dev->slot_index, index, false,
     80			    false);
     81	err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl);
     82	if (err) {
     83		dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query temp sensor\n");
     84		return err;
     85	}
     86	mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL, NULL, NULL);
     87	return sprintf(buf, "%d\n", temp);
     88}
     89
     90static ssize_t mlxsw_hwmon_temp_max_show(struct device *dev,
     91					 struct device_attribute *attr,
     92					 char *buf)
     93{
     94	struct mlxsw_hwmon_attr *mlxsw_hwmon_attr =
     95			container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
     96	struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev;
     97	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon;
     98	char mtmp_pl[MLXSW_REG_MTMP_LEN];
     99	int temp_max, index;
    100	int err;
    101
    102	index = mlxsw_hwmon_get_attr_index(mlxsw_hwmon_attr->type_index,
    103					   mlxsw_hwmon_dev->module_sensor_max);
    104	mlxsw_reg_mtmp_pack(mtmp_pl, mlxsw_hwmon_dev->slot_index, index, false,
    105			    false);
    106	err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl);
    107	if (err) {
    108		dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query temp sensor\n");
    109		return err;
    110	}
    111	mlxsw_reg_mtmp_unpack(mtmp_pl, NULL, &temp_max, NULL, NULL, NULL);
    112	return sprintf(buf, "%d\n", temp_max);
    113}
    114
    115static ssize_t mlxsw_hwmon_temp_rst_store(struct device *dev,
    116					  struct device_attribute *attr,
    117					  const char *buf, size_t len)
    118{
    119	struct mlxsw_hwmon_attr *mlxsw_hwmon_attr =
    120			container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
    121	struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev;
    122	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon;
    123	char mtmp_pl[MLXSW_REG_MTMP_LEN];
    124	unsigned long val;
    125	int index;
    126	int err;
    127
    128	err = kstrtoul(buf, 10, &val);
    129	if (err)
    130		return err;
    131	if (val != 1)
    132		return -EINVAL;
    133
    134	index = mlxsw_hwmon_get_attr_index(mlxsw_hwmon_attr->type_index,
    135					   mlxsw_hwmon_dev->module_sensor_max);
    136
    137	mlxsw_reg_mtmp_slot_index_set(mtmp_pl, mlxsw_hwmon_dev->slot_index);
    138	mlxsw_reg_mtmp_sensor_index_set(mtmp_pl, index);
    139	err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl);
    140	if (err)
    141		return err;
    142	mlxsw_reg_mtmp_mte_set(mtmp_pl, true);
    143	mlxsw_reg_mtmp_mtr_set(mtmp_pl, true);
    144	err = mlxsw_reg_write(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl);
    145	if (err) {
    146		dev_err(mlxsw_hwmon->bus_info->dev, "Failed to reset temp sensor history\n");
    147		return err;
    148	}
    149	return len;
    150}
    151
    152static ssize_t mlxsw_hwmon_fan_rpm_show(struct device *dev,
    153					struct device_attribute *attr,
    154					char *buf)
    155{
    156	struct mlxsw_hwmon_attr *mlxsw_hwmon_attr =
    157			container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
    158	struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev;
    159	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon;
    160	char mfsm_pl[MLXSW_REG_MFSM_LEN];
    161	int err;
    162
    163	mlxsw_reg_mfsm_pack(mfsm_pl, mlxsw_hwmon_attr->type_index);
    164	err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mfsm), mfsm_pl);
    165	if (err) {
    166		dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query fan\n");
    167		return err;
    168	}
    169	return sprintf(buf, "%u\n", mlxsw_reg_mfsm_rpm_get(mfsm_pl));
    170}
    171
    172static ssize_t mlxsw_hwmon_fan_fault_show(struct device *dev,
    173					  struct device_attribute *attr,
    174					  char *buf)
    175{
    176	struct mlxsw_hwmon_attr *mlxsw_hwmon_attr =
    177			container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
    178	struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev;
    179	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon;
    180	char fore_pl[MLXSW_REG_FORE_LEN];
    181	bool fault;
    182	int err;
    183
    184	err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(fore), fore_pl);
    185	if (err) {
    186		dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query fan\n");
    187		return err;
    188	}
    189	mlxsw_reg_fore_unpack(fore_pl, mlxsw_hwmon_attr->type_index, &fault);
    190
    191	return sprintf(buf, "%u\n", fault);
    192}
    193
    194static ssize_t mlxsw_hwmon_pwm_show(struct device *dev,
    195				    struct device_attribute *attr,
    196				    char *buf)
    197{
    198	struct mlxsw_hwmon_attr *mlxsw_hwmon_attr =
    199			container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
    200	struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev;
    201	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon;
    202	char mfsc_pl[MLXSW_REG_MFSC_LEN];
    203	int err;
    204
    205	mlxsw_reg_mfsc_pack(mfsc_pl, mlxsw_hwmon_attr->type_index, 0);
    206	err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mfsc), mfsc_pl);
    207	if (err) {
    208		dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query PWM\n");
    209		return err;
    210	}
    211	return sprintf(buf, "%u\n",
    212		       mlxsw_reg_mfsc_pwm_duty_cycle_get(mfsc_pl));
    213}
    214
    215static ssize_t mlxsw_hwmon_pwm_store(struct device *dev,
    216				     struct device_attribute *attr,
    217				     const char *buf, size_t len)
    218{
    219	struct mlxsw_hwmon_attr *mlxsw_hwmon_attr =
    220			container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
    221	struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev;
    222	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon;
    223	char mfsc_pl[MLXSW_REG_MFSC_LEN];
    224	unsigned long val;
    225	int err;
    226
    227	err = kstrtoul(buf, 10, &val);
    228	if (err)
    229		return err;
    230	if (val > 255)
    231		return -EINVAL;
    232
    233	mlxsw_reg_mfsc_pack(mfsc_pl, mlxsw_hwmon_attr->type_index, val);
    234	err = mlxsw_reg_write(mlxsw_hwmon->core, MLXSW_REG(mfsc), mfsc_pl);
    235	if (err) {
    236		dev_err(mlxsw_hwmon->bus_info->dev, "Failed to write PWM\n");
    237		return err;
    238	}
    239	return len;
    240}
    241
    242static int mlxsw_hwmon_module_temp_get(struct device *dev,
    243				       struct device_attribute *attr,
    244				       int *p_temp)
    245{
    246	struct mlxsw_hwmon_attr *mlxsw_hwmon_attr =
    247			container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
    248	struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev;
    249	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon;
    250	char mtmp_pl[MLXSW_REG_MTMP_LEN];
    251	u8 module;
    252	int err;
    253
    254	module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon_dev->sensor_count;
    255	mlxsw_reg_mtmp_pack(mtmp_pl, mlxsw_hwmon_dev->slot_index,
    256			    MLXSW_REG_MTMP_MODULE_INDEX_MIN + module, false,
    257			    false);
    258	err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl);
    259	if (err) {
    260		dev_err(dev, "Failed to query module temperature\n");
    261		return err;
    262	}
    263	mlxsw_reg_mtmp_unpack(mtmp_pl, p_temp, NULL, NULL, NULL, NULL);
    264
    265	return 0;
    266}
    267
    268static ssize_t mlxsw_hwmon_module_temp_show(struct device *dev,
    269					    struct device_attribute *attr,
    270					    char *buf)
    271{
    272	int err, temp;
    273
    274	err = mlxsw_hwmon_module_temp_get(dev, attr, &temp);
    275	if (err)
    276		return err;
    277
    278	return sprintf(buf, "%d\n", temp);
    279}
    280
    281static ssize_t mlxsw_hwmon_module_temp_fault_show(struct device *dev,
    282						  struct device_attribute *attr,
    283						  char *buf)
    284{
    285	struct mlxsw_hwmon_attr *mlxsw_hwmon_attr =
    286			container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
    287	struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev;
    288	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon;
    289	char mtbr_pl[MLXSW_REG_MTBR_LEN] = {0};
    290	u8 module, fault;
    291	u16 temp;
    292	int err;
    293
    294	module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon_dev->sensor_count;
    295	mlxsw_reg_mtbr_pack(mtbr_pl, mlxsw_hwmon_dev->slot_index,
    296			    MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, 1);
    297	err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtbr), mtbr_pl);
    298	if (err) {
    299		dev_err(dev, "Failed to query module temperature sensor\n");
    300		return err;
    301	}
    302
    303	mlxsw_reg_mtbr_temp_unpack(mtbr_pl, 0, &temp, NULL);
    304
    305	/* Update status and temperature cache. */
    306	switch (temp) {
    307	case MLXSW_REG_MTBR_BAD_SENS_INFO:
    308		/* Untrusted cable is connected. Reading temperature from its
    309		 * sensor is faulty.
    310		 */
    311		fault = 1;
    312		break;
    313	case MLXSW_REG_MTBR_NO_CONN:
    314	case MLXSW_REG_MTBR_NO_TEMP_SENS:
    315	case MLXSW_REG_MTBR_INDEX_NA:
    316	default:
    317		fault = 0;
    318		break;
    319	}
    320
    321	return sprintf(buf, "%u\n", fault);
    322}
    323
    324static int mlxsw_hwmon_module_temp_critical_get(struct device *dev,
    325						struct device_attribute *attr,
    326						int *p_temp)
    327{
    328	struct mlxsw_hwmon_attr *mlxsw_hwmon_attr =
    329			container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
    330	struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev;
    331	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon;
    332	u8 module;
    333	int err;
    334
    335	module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon_dev->sensor_count;
    336	err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core,
    337						   mlxsw_hwmon_dev->slot_index,
    338						   module, SFP_TEMP_HIGH_WARN,
    339						   p_temp);
    340	if (err) {
    341		dev_err(dev, "Failed to query module temperature thresholds\n");
    342		return err;
    343	}
    344
    345	return 0;
    346}
    347
    348static ssize_t
    349mlxsw_hwmon_module_temp_critical_show(struct device *dev,
    350				      struct device_attribute *attr, char *buf)
    351{
    352	int err, temp;
    353
    354	err = mlxsw_hwmon_module_temp_critical_get(dev, attr, &temp);
    355	if (err)
    356		return err;
    357
    358	return sprintf(buf, "%u\n", temp);
    359}
    360
    361static int mlxsw_hwmon_module_temp_emergency_get(struct device *dev,
    362						 struct device_attribute *attr,
    363						 int *p_temp)
    364{
    365	struct mlxsw_hwmon_attr *mlxsw_hwmon_attr =
    366			container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
    367	struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev;
    368	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon;
    369	u8 module;
    370	int err;
    371
    372	module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon_dev->sensor_count;
    373	err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core,
    374						   mlxsw_hwmon_dev->slot_index,
    375						   module, SFP_TEMP_HIGH_ALARM,
    376						   p_temp);
    377	if (err) {
    378		dev_err(dev, "Failed to query module temperature thresholds\n");
    379		return err;
    380	}
    381
    382	return 0;
    383}
    384
    385static ssize_t
    386mlxsw_hwmon_module_temp_emergency_show(struct device *dev,
    387				       struct device_attribute *attr,
    388				       char *buf)
    389{
    390	int err, temp;
    391
    392	err = mlxsw_hwmon_module_temp_emergency_get(dev, attr, &temp);
    393	if (err)
    394		return err;
    395
    396	return sprintf(buf, "%u\n", temp);
    397}
    398
    399static ssize_t
    400mlxsw_hwmon_module_temp_label_show(struct device *dev,
    401				   struct device_attribute *attr,
    402				   char *buf)
    403{
    404	struct mlxsw_hwmon_attr *mlxsw_hwmon_attr =
    405			container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
    406
    407	return sprintf(buf, "front panel %03u\n",
    408		       mlxsw_hwmon_attr->type_index);
    409}
    410
    411static ssize_t
    412mlxsw_hwmon_gbox_temp_label_show(struct device *dev,
    413				 struct device_attribute *attr,
    414				 char *buf)
    415{
    416	struct mlxsw_hwmon_attr *mlxsw_hwmon_attr =
    417			container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
    418	struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev;
    419	int index = mlxsw_hwmon_attr->type_index -
    420		    mlxsw_hwmon_dev->module_sensor_max + 1;
    421
    422	return sprintf(buf, "gearbox %03u\n", index);
    423}
    424
    425static ssize_t mlxsw_hwmon_temp_critical_alarm_show(struct device *dev,
    426						    struct device_attribute *attr,
    427						    char *buf)
    428{
    429	int err, temp, emergency_temp, critic_temp;
    430
    431	err = mlxsw_hwmon_module_temp_get(dev, attr, &temp);
    432	if (err)
    433		return err;
    434
    435	if (temp <= 0)
    436		return sprintf(buf, "%d\n", false);
    437
    438	err = mlxsw_hwmon_module_temp_emergency_get(dev, attr, &emergency_temp);
    439	if (err)
    440		return err;
    441
    442	if (temp >= emergency_temp)
    443		return sprintf(buf, "%d\n", false);
    444
    445	err = mlxsw_hwmon_module_temp_critical_get(dev, attr, &critic_temp);
    446	if (err)
    447		return err;
    448
    449	return sprintf(buf, "%d\n", temp >= critic_temp);
    450}
    451
    452static ssize_t mlxsw_hwmon_temp_emergency_alarm_show(struct device *dev,
    453						     struct device_attribute *attr,
    454						     char *buf)
    455{
    456	int err, temp, emergency_temp;
    457
    458	err = mlxsw_hwmon_module_temp_get(dev, attr, &temp);
    459	if (err)
    460		return err;
    461
    462	if (temp <= 0)
    463		return sprintf(buf, "%d\n", false);
    464
    465	err = mlxsw_hwmon_module_temp_emergency_get(dev, attr, &emergency_temp);
    466	if (err)
    467		return err;
    468
    469	return sprintf(buf, "%d\n", temp >= emergency_temp);
    470}
    471
    472enum mlxsw_hwmon_attr_type {
    473	MLXSW_HWMON_ATTR_TYPE_TEMP,
    474	MLXSW_HWMON_ATTR_TYPE_TEMP_MAX,
    475	MLXSW_HWMON_ATTR_TYPE_TEMP_RST,
    476	MLXSW_HWMON_ATTR_TYPE_FAN_RPM,
    477	MLXSW_HWMON_ATTR_TYPE_FAN_FAULT,
    478	MLXSW_HWMON_ATTR_TYPE_PWM,
    479	MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE,
    480	MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_FAULT,
    481	MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_CRIT,
    482	MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_EMERG,
    483	MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_LABEL,
    484	MLXSW_HWMON_ATTR_TYPE_TEMP_GBOX_LABEL,
    485	MLXSW_HWMON_ATTR_TYPE_TEMP_CRIT_ALARM,
    486	MLXSW_HWMON_ATTR_TYPE_TEMP_EMERGENCY_ALARM,
    487};
    488
    489static void mlxsw_hwmon_attr_add(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev,
    490				 enum mlxsw_hwmon_attr_type attr_type,
    491				 unsigned int type_index, unsigned int num)
    492{
    493	struct mlxsw_hwmon_attr *mlxsw_hwmon_attr;
    494	unsigned int attr_index;
    495
    496	attr_index = mlxsw_hwmon_dev->attrs_count;
    497	mlxsw_hwmon_attr = &mlxsw_hwmon_dev->hwmon_attrs[attr_index];
    498
    499	switch (attr_type) {
    500	case MLXSW_HWMON_ATTR_TYPE_TEMP:
    501		mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_temp_show;
    502		mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
    503		snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
    504			 "temp%u_input", num + 1);
    505		break;
    506	case MLXSW_HWMON_ATTR_TYPE_TEMP_MAX:
    507		mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_temp_max_show;
    508		mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
    509		snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
    510			 "temp%u_highest", num + 1);
    511		break;
    512	case MLXSW_HWMON_ATTR_TYPE_TEMP_RST:
    513		mlxsw_hwmon_attr->dev_attr.store = mlxsw_hwmon_temp_rst_store;
    514		mlxsw_hwmon_attr->dev_attr.attr.mode = 0200;
    515		snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
    516			 "temp%u_reset_history", num + 1);
    517		break;
    518	case MLXSW_HWMON_ATTR_TYPE_FAN_RPM:
    519		mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_fan_rpm_show;
    520		mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
    521		snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
    522			 "fan%u_input", num + 1);
    523		break;
    524	case MLXSW_HWMON_ATTR_TYPE_FAN_FAULT:
    525		mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_fan_fault_show;
    526		mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
    527		snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
    528			 "fan%u_fault", num + 1);
    529		break;
    530	case MLXSW_HWMON_ATTR_TYPE_PWM:
    531		mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_pwm_show;
    532		mlxsw_hwmon_attr->dev_attr.store = mlxsw_hwmon_pwm_store;
    533		mlxsw_hwmon_attr->dev_attr.attr.mode = 0644;
    534		snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
    535			 "pwm%u", num + 1);
    536		break;
    537	case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE:
    538		mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_module_temp_show;
    539		mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
    540		snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
    541			 "temp%u_input", num + 1);
    542		break;
    543	case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_FAULT:
    544		mlxsw_hwmon_attr->dev_attr.show =
    545					mlxsw_hwmon_module_temp_fault_show;
    546		mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
    547		snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
    548			 "temp%u_fault", num + 1);
    549		break;
    550	case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_CRIT:
    551		mlxsw_hwmon_attr->dev_attr.show =
    552			mlxsw_hwmon_module_temp_critical_show;
    553		mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
    554		snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
    555			 "temp%u_crit", num + 1);
    556		break;
    557	case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_EMERG:
    558		mlxsw_hwmon_attr->dev_attr.show =
    559			mlxsw_hwmon_module_temp_emergency_show;
    560		mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
    561		snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
    562			 "temp%u_emergency", num + 1);
    563		break;
    564	case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_LABEL:
    565		mlxsw_hwmon_attr->dev_attr.show =
    566			mlxsw_hwmon_module_temp_label_show;
    567		mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
    568		snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
    569			 "temp%u_label", num + 1);
    570		break;
    571	case MLXSW_HWMON_ATTR_TYPE_TEMP_GBOX_LABEL:
    572		mlxsw_hwmon_attr->dev_attr.show =
    573			mlxsw_hwmon_gbox_temp_label_show;
    574		mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
    575		snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
    576			 "temp%u_label", num + 1);
    577		break;
    578	case MLXSW_HWMON_ATTR_TYPE_TEMP_CRIT_ALARM:
    579		mlxsw_hwmon_attr->dev_attr.show =
    580			mlxsw_hwmon_temp_critical_alarm_show;
    581		mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
    582		snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
    583			 "temp%u_crit_alarm", num + 1);
    584		break;
    585	case MLXSW_HWMON_ATTR_TYPE_TEMP_EMERGENCY_ALARM:
    586		mlxsw_hwmon_attr->dev_attr.show =
    587			mlxsw_hwmon_temp_emergency_alarm_show;
    588		mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
    589		snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
    590			 "temp%u_emergency_alarm", num + 1);
    591		break;
    592	default:
    593		WARN_ON(1);
    594	}
    595
    596	mlxsw_hwmon_attr->type_index = type_index;
    597	mlxsw_hwmon_attr->mlxsw_hwmon_dev = mlxsw_hwmon_dev;
    598	mlxsw_hwmon_attr->dev_attr.attr.name = mlxsw_hwmon_attr->name;
    599	sysfs_attr_init(&mlxsw_hwmon_attr->dev_attr.attr);
    600
    601	mlxsw_hwmon_dev->attrs[attr_index] = &mlxsw_hwmon_attr->dev_attr.attr;
    602	mlxsw_hwmon_dev->attrs_count++;
    603}
    604
    605static int mlxsw_hwmon_temp_init(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev)
    606{
    607	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon;
    608	char mtcap_pl[MLXSW_REG_MTCAP_LEN] = {0};
    609	int i;
    610	int err;
    611
    612	err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtcap), mtcap_pl);
    613	if (err) {
    614		dev_err(mlxsw_hwmon->bus_info->dev, "Failed to get number of temp sensors\n");
    615		return err;
    616	}
    617	mlxsw_hwmon_dev->sensor_count = mlxsw_reg_mtcap_sensor_count_get(mtcap_pl);
    618	for (i = 0; i < mlxsw_hwmon_dev->sensor_count; i++) {
    619		char mtmp_pl[MLXSW_REG_MTMP_LEN] = {0};
    620
    621		mlxsw_reg_mtmp_slot_index_set(mtmp_pl,
    622					      mlxsw_hwmon_dev->slot_index);
    623		mlxsw_reg_mtmp_sensor_index_set(mtmp_pl, i);
    624		err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp),
    625				      mtmp_pl);
    626		if (err)
    627			return err;
    628		mlxsw_reg_mtmp_mte_set(mtmp_pl, true);
    629		mlxsw_reg_mtmp_mtr_set(mtmp_pl, true);
    630		err = mlxsw_reg_write(mlxsw_hwmon->core,
    631				      MLXSW_REG(mtmp), mtmp_pl);
    632		if (err) {
    633			dev_err(mlxsw_hwmon->bus_info->dev, "Failed to setup temp sensor number %d\n",
    634				i);
    635			return err;
    636		}
    637		mlxsw_hwmon_attr_add(mlxsw_hwmon_dev,
    638				     MLXSW_HWMON_ATTR_TYPE_TEMP, i, i);
    639		mlxsw_hwmon_attr_add(mlxsw_hwmon_dev,
    640				     MLXSW_HWMON_ATTR_TYPE_TEMP_MAX, i, i);
    641		mlxsw_hwmon_attr_add(mlxsw_hwmon_dev,
    642				     MLXSW_HWMON_ATTR_TYPE_TEMP_RST, i, i);
    643	}
    644	return 0;
    645}
    646
    647static int mlxsw_hwmon_fans_init(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev)
    648{
    649	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon;
    650	char mfcr_pl[MLXSW_REG_MFCR_LEN] = {0};
    651	enum mlxsw_reg_mfcr_pwm_frequency freq;
    652	unsigned int type_index;
    653	unsigned int num;
    654	u16 tacho_active;
    655	u8 pwm_active;
    656	int err;
    657
    658	err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mfcr), mfcr_pl);
    659	if (err) {
    660		dev_err(mlxsw_hwmon->bus_info->dev, "Failed to get to probe PWMs and Tachometers\n");
    661		return err;
    662	}
    663	mlxsw_reg_mfcr_unpack(mfcr_pl, &freq, &tacho_active, &pwm_active);
    664	num = 0;
    665	for (type_index = 0; type_index < MLXSW_MFCR_TACHOS_MAX; type_index++) {
    666		if (tacho_active & BIT(type_index)) {
    667			mlxsw_hwmon_attr_add(mlxsw_hwmon_dev,
    668					     MLXSW_HWMON_ATTR_TYPE_FAN_RPM,
    669					     type_index, num);
    670			mlxsw_hwmon_attr_add(mlxsw_hwmon_dev,
    671					     MLXSW_HWMON_ATTR_TYPE_FAN_FAULT,
    672					     type_index, num++);
    673		}
    674	}
    675	num = 0;
    676	for (type_index = 0; type_index < MLXSW_MFCR_PWMS_MAX; type_index++) {
    677		if (pwm_active & BIT(type_index))
    678			mlxsw_hwmon_attr_add(mlxsw_hwmon_dev,
    679					     MLXSW_HWMON_ATTR_TYPE_PWM,
    680					     type_index, num++);
    681	}
    682	return 0;
    683}
    684
    685static int mlxsw_hwmon_module_init(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev)
    686{
    687	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon;
    688	char mgpir_pl[MLXSW_REG_MGPIR_LEN];
    689	u8 module_sensor_max;
    690	int i, err;
    691
    692	mlxsw_reg_mgpir_pack(mgpir_pl, mlxsw_hwmon_dev->slot_index);
    693	err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mgpir), mgpir_pl);
    694	if (err)
    695		return err;
    696
    697	mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL,
    698			       &module_sensor_max, NULL);
    699
    700	/* Add extra attributes for module temperature. Sensor index is
    701	 * assigned to sensor_count value, while all indexed before
    702	 * sensor_count are already utilized by the sensors connected through
    703	 * mtmp register by mlxsw_hwmon_temp_init().
    704	 */
    705	mlxsw_hwmon_dev->module_sensor_max = mlxsw_hwmon_dev->sensor_count +
    706					     module_sensor_max;
    707	for (i = mlxsw_hwmon_dev->sensor_count;
    708	     i < mlxsw_hwmon_dev->module_sensor_max; i++) {
    709		mlxsw_hwmon_attr_add(mlxsw_hwmon_dev,
    710				     MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE, i, i);
    711		mlxsw_hwmon_attr_add(mlxsw_hwmon_dev,
    712				     MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_FAULT,
    713				     i, i);
    714		mlxsw_hwmon_attr_add(mlxsw_hwmon_dev,
    715				     MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_CRIT, i,
    716				     i);
    717		mlxsw_hwmon_attr_add(mlxsw_hwmon_dev,
    718				     MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_EMERG,
    719				     i, i);
    720		mlxsw_hwmon_attr_add(mlxsw_hwmon_dev,
    721				     MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_LABEL,
    722				     i, i);
    723		mlxsw_hwmon_attr_add(mlxsw_hwmon_dev,
    724				     MLXSW_HWMON_ATTR_TYPE_TEMP_CRIT_ALARM,
    725				     i, i);
    726		mlxsw_hwmon_attr_add(mlxsw_hwmon_dev,
    727				     MLXSW_HWMON_ATTR_TYPE_TEMP_EMERGENCY_ALARM,
    728				     i, i);
    729	}
    730
    731	return 0;
    732}
    733
    734static int mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev)
    735{
    736	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon;
    737	enum mlxsw_reg_mgpir_device_type device_type;
    738	int index, max_index, sensor_index;
    739	char mgpir_pl[MLXSW_REG_MGPIR_LEN];
    740	char mtmp_pl[MLXSW_REG_MTMP_LEN];
    741	u8 gbox_num;
    742	int err;
    743
    744	mlxsw_reg_mgpir_pack(mgpir_pl, mlxsw_hwmon_dev->slot_index);
    745	err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mgpir), mgpir_pl);
    746	if (err)
    747		return err;
    748
    749	mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, &device_type, NULL, NULL,
    750			       NULL);
    751	if (device_type != MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE ||
    752	    !gbox_num)
    753		return 0;
    754
    755	index = mlxsw_hwmon_dev->module_sensor_max;
    756	max_index = mlxsw_hwmon_dev->module_sensor_max + gbox_num;
    757	while (index < max_index) {
    758		sensor_index = index % mlxsw_hwmon_dev->module_sensor_max +
    759			       MLXSW_REG_MTMP_GBOX_INDEX_MIN;
    760		mlxsw_reg_mtmp_pack(mtmp_pl, mlxsw_hwmon_dev->slot_index,
    761				    sensor_index, true, true);
    762		err = mlxsw_reg_write(mlxsw_hwmon->core,
    763				      MLXSW_REG(mtmp), mtmp_pl);
    764		if (err) {
    765			dev_err(mlxsw_hwmon->bus_info->dev, "Failed to setup temp sensor number %d\n",
    766				sensor_index);
    767			return err;
    768		}
    769		mlxsw_hwmon_attr_add(mlxsw_hwmon_dev,
    770				     MLXSW_HWMON_ATTR_TYPE_TEMP, index, index);
    771		mlxsw_hwmon_attr_add(mlxsw_hwmon_dev,
    772				     MLXSW_HWMON_ATTR_TYPE_TEMP_MAX, index,
    773				     index);
    774		mlxsw_hwmon_attr_add(mlxsw_hwmon_dev,
    775				     MLXSW_HWMON_ATTR_TYPE_TEMP_RST, index,
    776				     index);
    777		mlxsw_hwmon_attr_add(mlxsw_hwmon_dev,
    778				     MLXSW_HWMON_ATTR_TYPE_TEMP_GBOX_LABEL,
    779				     index, index);
    780		index++;
    781	}
    782
    783	return 0;
    784}
    785
    786static void
    787mlxsw_hwmon_got_active(struct mlxsw_core *mlxsw_core, u8 slot_index,
    788		       void *priv)
    789{
    790	struct mlxsw_hwmon *hwmon = priv;
    791	struct mlxsw_hwmon_dev *linecard;
    792	struct device *dev;
    793	int err;
    794
    795	dev = hwmon->bus_info->dev;
    796	linecard = &hwmon->line_cards[slot_index];
    797	if (linecard->active)
    798		return;
    799	/* For the main board, module sensor indexes start from 1, sensor index
    800	 * 0 is used for the ASIC. Use the same numbering for line cards.
    801	 */
    802	linecard->sensor_count = 1;
    803	linecard->slot_index = slot_index;
    804	linecard->hwmon = hwmon;
    805	err = mlxsw_hwmon_module_init(linecard);
    806	if (err) {
    807		dev_err(dev, "Failed to configure hwmon objects for line card modules in slot %d\n",
    808			slot_index);
    809		return;
    810	}
    811
    812	err = mlxsw_hwmon_gearbox_init(linecard);
    813	if (err) {
    814		dev_err(dev, "Failed to configure hwmon objects for line card gearboxes in slot %d\n",
    815			slot_index);
    816		return;
    817	}
    818
    819	linecard->groups[0] = &linecard->group;
    820	linecard->group.attrs = linecard->attrs;
    821	sprintf(linecard->name, "%s#%02u", "linecard", slot_index);
    822	linecard->hwmon_dev =
    823		hwmon_device_register_with_groups(dev, linecard->name,
    824						  linecard, linecard->groups);
    825	if (IS_ERR(linecard->hwmon_dev)) {
    826		dev_err(dev, "Failed to register hwmon objects for line card in slot %d\n",
    827			slot_index);
    828		return;
    829	}
    830
    831	linecard->active = true;
    832}
    833
    834static void
    835mlxsw_hwmon_got_inactive(struct mlxsw_core *mlxsw_core, u8 slot_index,
    836			 void *priv)
    837{
    838	struct mlxsw_hwmon *hwmon = priv;
    839	struct mlxsw_hwmon_dev *linecard;
    840
    841	linecard = &hwmon->line_cards[slot_index];
    842	if (!linecard->active)
    843		return;
    844	linecard->active = false;
    845	hwmon_device_unregister(linecard->hwmon_dev);
    846	/* Reset attributes counter */
    847	linecard->attrs_count = 0;
    848}
    849
    850static struct mlxsw_linecards_event_ops mlxsw_hwmon_event_ops = {
    851	.got_active = mlxsw_hwmon_got_active,
    852	.got_inactive = mlxsw_hwmon_got_inactive,
    853};
    854
    855int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core,
    856		     const struct mlxsw_bus_info *mlxsw_bus_info,
    857		     struct mlxsw_hwmon **p_hwmon)
    858{
    859	char mgpir_pl[MLXSW_REG_MGPIR_LEN];
    860	struct mlxsw_hwmon *mlxsw_hwmon;
    861	struct device *hwmon_dev;
    862	u8 num_of_slots;
    863	int err;
    864
    865	mlxsw_reg_mgpir_pack(mgpir_pl, 0);
    866	err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mgpir), mgpir_pl);
    867	if (err)
    868		return err;
    869
    870	mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, NULL,
    871			       &num_of_slots);
    872
    873	mlxsw_hwmon = kzalloc(struct_size(mlxsw_hwmon, line_cards,
    874					  num_of_slots + 1), GFP_KERNEL);
    875	if (!mlxsw_hwmon)
    876		return -ENOMEM;
    877
    878	mlxsw_hwmon->core = mlxsw_core;
    879	mlxsw_hwmon->bus_info = mlxsw_bus_info;
    880	mlxsw_hwmon->line_cards[0].hwmon = mlxsw_hwmon;
    881	mlxsw_hwmon->line_cards[0].slot_index = 0;
    882
    883	err = mlxsw_hwmon_temp_init(&mlxsw_hwmon->line_cards[0]);
    884	if (err)
    885		goto err_temp_init;
    886
    887	err = mlxsw_hwmon_fans_init(&mlxsw_hwmon->line_cards[0]);
    888	if (err)
    889		goto err_fans_init;
    890
    891	err = mlxsw_hwmon_module_init(&mlxsw_hwmon->line_cards[0]);
    892	if (err)
    893		goto err_temp_module_init;
    894
    895	err = mlxsw_hwmon_gearbox_init(&mlxsw_hwmon->line_cards[0]);
    896	if (err)
    897		goto err_temp_gearbox_init;
    898
    899	mlxsw_hwmon->line_cards[0].groups[0] = &mlxsw_hwmon->line_cards[0].group;
    900	mlxsw_hwmon->line_cards[0].group.attrs = mlxsw_hwmon->line_cards[0].attrs;
    901
    902	hwmon_dev = hwmon_device_register_with_groups(mlxsw_bus_info->dev,
    903						      "mlxsw",
    904						      &mlxsw_hwmon->line_cards[0],
    905						      mlxsw_hwmon->line_cards[0].groups);
    906	if (IS_ERR(hwmon_dev)) {
    907		err = PTR_ERR(hwmon_dev);
    908		goto err_hwmon_register;
    909	}
    910
    911	err = mlxsw_linecards_event_ops_register(mlxsw_hwmon->core,
    912						 &mlxsw_hwmon_event_ops,
    913						 mlxsw_hwmon);
    914	if (err)
    915		goto err_linecards_event_ops_register;
    916
    917	mlxsw_hwmon->line_cards[0].hwmon_dev = hwmon_dev;
    918	mlxsw_hwmon->line_cards[0].active = true;
    919	*p_hwmon = mlxsw_hwmon;
    920	return 0;
    921
    922err_linecards_event_ops_register:
    923	hwmon_device_unregister(mlxsw_hwmon->line_cards[0].hwmon_dev);
    924err_hwmon_register:
    925err_temp_gearbox_init:
    926err_temp_module_init:
    927err_fans_init:
    928err_temp_init:
    929	kfree(mlxsw_hwmon);
    930	return err;
    931}
    932
    933void mlxsw_hwmon_fini(struct mlxsw_hwmon *mlxsw_hwmon)
    934{
    935	mlxsw_hwmon->line_cards[0].active = false;
    936	mlxsw_linecards_event_ops_unregister(mlxsw_hwmon->core,
    937					     &mlxsw_hwmon_event_ops, mlxsw_hwmon);
    938	hwmon_device_unregister(mlxsw_hwmon->line_cards[0].hwmon_dev);
    939	kfree(mlxsw_hwmon);
    940}