Skip to content

Commit

Permalink
mlxsw: core: Extend hwmon interface with QSFP module temperature attr…
Browse files Browse the repository at this point in the history
…ibutes

Add new attributes to hwmon object for exposing QSFP module temperature
input, fault indication, critical and emergency thresholds. Temperature
input and fault indication are read from Management Temperature Bulk
Register. Temperature thresholds are read from Management Cable Info
Access Register.

Signed-off-by: Vadim Pasternak <vadimp@mellanox.com>
Reviewed-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Vadim Pasternak authored and David S. Miller committed Feb 14, 2019
1 parent 2c6a33c commit 5c42eaa
Showing 1 changed file with 215 additions and 3 deletions.
218 changes: 215 additions & 3 deletions drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
#include <linux/sysfs.h>
#include <linux/hwmon.h>
#include <linux/err.h>
#include <linux/sfp.h>

#include "core.h"
#include "core_env.h"

#define MLXSW_HWMON_TEMP_SENSOR_MAX_COUNT 127
#define MLXSW_HWMON_ATTR_COUNT (MLXSW_HWMON_TEMP_SENSOR_MAX_COUNT * 4 + \
Expand All @@ -30,6 +32,7 @@ struct mlxsw_hwmon {
struct attribute *attrs[MLXSW_HWMON_ATTR_COUNT + 1];
struct mlxsw_hwmon_attr hwmon_attrs[MLXSW_HWMON_ATTR_COUNT];
unsigned int attrs_count;
u8 sensor_count;
};

static ssize_t mlxsw_hwmon_temp_show(struct device *dev,
Expand Down Expand Up @@ -188,13 +191,147 @@ static ssize_t mlxsw_hwmon_pwm_store(struct device *dev,
return len;
}

static ssize_t mlxsw_hwmon_module_temp_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct mlxsw_hwmon_attr *mlwsw_hwmon_attr =
container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
char mtbr_pl[MLXSW_REG_MTBR_LEN] = {0};
u16 temp;
u8 module;
int err;

module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count;
mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module,
1);
err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtbr), mtbr_pl);
if (err) {
dev_err(dev, "Failed to query module temprature sensor\n");
return err;
}

mlxsw_reg_mtbr_temp_unpack(mtbr_pl, 0, &temp, NULL);
/* Update status and temperature cache. */
switch (temp) {
case MLXSW_REG_MTBR_NO_CONN: /* fall-through */
case MLXSW_REG_MTBR_NO_TEMP_SENS: /* fall-through */
case MLXSW_REG_MTBR_INDEX_NA:
temp = 0;
break;
case MLXSW_REG_MTBR_BAD_SENS_INFO:
/* Untrusted cable is connected. Reading temperature from its
* sensor is faulty.
*/
temp = 0;
break;
default:
temp = MLXSW_REG_MTMP_TEMP_TO_MC(temp);
break;
}

return sprintf(buf, "%u\n", temp);
}

static ssize_t mlxsw_hwmon_module_temp_fault_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct mlxsw_hwmon_attr *mlwsw_hwmon_attr =
container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
char mtbr_pl[MLXSW_REG_MTBR_LEN] = {0};
u8 module, fault;
u16 temp;
int err;

module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count;
mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module,
1);
err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtbr), mtbr_pl);
if (err) {
dev_err(dev, "Failed to query module temprature sensor\n");
return err;
}

mlxsw_reg_mtbr_temp_unpack(mtbr_pl, 0, &temp, NULL);

/* Update status and temperature cache. */
switch (temp) {
case MLXSW_REG_MTBR_BAD_SENS_INFO:
/* Untrusted cable is connected. Reading temperature from its
* sensor is faulty.
*/
fault = 1;
break;
case MLXSW_REG_MTBR_NO_CONN: /* fall-through */
case MLXSW_REG_MTBR_NO_TEMP_SENS: /* fall-through */
case MLXSW_REG_MTBR_INDEX_NA:
default:
fault = 0;
break;
}

return sprintf(buf, "%u\n", fault);
}

static ssize_t
mlxsw_hwmon_module_temp_critical_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mlxsw_hwmon_attr *mlwsw_hwmon_attr =
container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
int temp;
u8 module;
int err;

module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count;
err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, module,
SFP_TEMP_HIGH_WARN, &temp);
if (err) {
dev_err(dev, "Failed to query module temprature thresholds\n");
return err;
}

return sprintf(buf, "%u\n", temp);
}

static ssize_t
mlxsw_hwmon_module_temp_emergency_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct mlxsw_hwmon_attr *mlwsw_hwmon_attr =
container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
u8 module;
int temp;
int err;

module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count;
err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, module,
SFP_TEMP_HIGH_ALARM, &temp);
if (err) {
dev_err(dev, "Failed to query module temprature thresholds\n");
return err;
}

return sprintf(buf, "%u\n", temp);
}

enum mlxsw_hwmon_attr_type {
MLXSW_HWMON_ATTR_TYPE_TEMP,
MLXSW_HWMON_ATTR_TYPE_TEMP_MAX,
MLXSW_HWMON_ATTR_TYPE_TEMP_RST,
MLXSW_HWMON_ATTR_TYPE_FAN_RPM,
MLXSW_HWMON_ATTR_TYPE_FAN_FAULT,
MLXSW_HWMON_ATTR_TYPE_PWM,
MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE,
MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_FAULT,
MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_CRIT,
MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_EMERG,
};

static void mlxsw_hwmon_attr_add(struct mlxsw_hwmon *mlxsw_hwmon,
Expand Down Expand Up @@ -244,6 +381,33 @@ static void mlxsw_hwmon_attr_add(struct mlxsw_hwmon *mlxsw_hwmon,
snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
"pwm%u", num + 1);
break;
case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE:
mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_module_temp_show;
mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
"temp%u_input", num + 1);
break;
case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_FAULT:
mlxsw_hwmon_attr->dev_attr.show =
mlxsw_hwmon_module_temp_fault_show;
mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
"temp%u_fault", num + 1);
break;
case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_CRIT:
mlxsw_hwmon_attr->dev_attr.show =
mlxsw_hwmon_module_temp_critical_show;
mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
"temp%u_crit", num + 1);
break;
case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_EMERG:
mlxsw_hwmon_attr->dev_attr.show =
mlxsw_hwmon_module_temp_emergency_show;
mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
"temp%u_emergency", num + 1);
break;
default:
WARN_ON(1);
}
Expand All @@ -261,7 +425,6 @@ static int mlxsw_hwmon_temp_init(struct mlxsw_hwmon *mlxsw_hwmon)
{
char mtcap_pl[MLXSW_REG_MTCAP_LEN] = {0};
char mtmp_pl[MLXSW_REG_MTMP_LEN];
u8 sensor_count;
int i;
int err;

Expand All @@ -270,8 +433,8 @@ static int mlxsw_hwmon_temp_init(struct mlxsw_hwmon *mlxsw_hwmon)
dev_err(mlxsw_hwmon->bus_info->dev, "Failed to get number of temp sensors\n");
return err;
}
sensor_count = mlxsw_reg_mtcap_sensor_count_get(mtcap_pl);
for (i = 0; i < sensor_count; i++) {
mlxsw_hwmon->sensor_count = mlxsw_reg_mtcap_sensor_count_get(mtcap_pl);
for (i = 0; i < mlxsw_hwmon->sensor_count; i++) {
mlxsw_reg_mtmp_pack(mtmp_pl, i, true, true);
err = mlxsw_reg_write(mlxsw_hwmon->core,
MLXSW_REG(mtmp), mtmp_pl);
Expand Down Expand Up @@ -327,6 +490,50 @@ static int mlxsw_hwmon_fans_init(struct mlxsw_hwmon *mlxsw_hwmon)
return 0;
}

static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon)
{
unsigned int module_count = mlxsw_core_max_ports(mlxsw_hwmon->core);
char pmlp_pl[MLXSW_REG_PMLP_LEN] = {0};
int i, index;
u8 width;
int err;

/* Add extra attributes for module temperature. Sensor index is
* assigned to sensor_count value, while all indexed before
* sensor_count are already utilized by the sensors connected through
* mtmp register by mlxsw_hwmon_temp_init().
*/
index = mlxsw_hwmon->sensor_count;
for (i = 1; i < module_count; i++) {
mlxsw_reg_pmlp_pack(pmlp_pl, i);
err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(pmlp),
pmlp_pl);
if (err) {
dev_err(mlxsw_hwmon->bus_info->dev, "Failed to read module index %d\n",
i);
return err;
}
width = mlxsw_reg_pmlp_width_get(pmlp_pl);
if (!width)
continue;
mlxsw_hwmon_attr_add(mlxsw_hwmon,
MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE, index,
index);
mlxsw_hwmon_attr_add(mlxsw_hwmon,
MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_FAULT,
index, index);
mlxsw_hwmon_attr_add(mlxsw_hwmon,
MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_CRIT,
index, index);
mlxsw_hwmon_attr_add(mlxsw_hwmon,
MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_EMERG,
index, index);
index++;
}

return 0;
}

int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core,
const struct mlxsw_bus_info *mlxsw_bus_info,
struct mlxsw_hwmon **p_hwmon)
Expand All @@ -349,6 +556,10 @@ int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core,
if (err)
goto err_fans_init;

err = mlxsw_hwmon_module_init(mlxsw_hwmon);
if (err)
goto err_temp_module_init;

mlxsw_hwmon->groups[0] = &mlxsw_hwmon->group;
mlxsw_hwmon->group.attrs = mlxsw_hwmon->attrs;

Expand All @@ -365,6 +576,7 @@ int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core,
return 0;

err_hwmon_register:
err_temp_module_init:
err_fans_init:
err_temp_init:
kfree(mlxsw_hwmon);
Expand Down

0 comments on commit 5c42eaa

Please sign in to comment.