Skip to content

Commit 5c42eaa

Browse files
mellanoxbmcdavem330
authored andcommitted
mlxsw: core: Extend hwmon interface with QSFP module temperature attributes
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 <[email protected]> Reviewed-by: Jiri Pirko <[email protected]> Signed-off-by: Ido Schimmel <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 2c6a33c commit 5c42eaa

File tree

1 file changed

+215
-3
lines changed

1 file changed

+215
-3
lines changed

drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c

Lines changed: 215 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77
#include <linux/sysfs.h>
88
#include <linux/hwmon.h>
99
#include <linux/err.h>
10+
#include <linux/sfp.h>
1011

1112
#include "core.h"
13+
#include "core_env.h"
1214

1315
#define MLXSW_HWMON_TEMP_SENSOR_MAX_COUNT 127
1416
#define MLXSW_HWMON_ATTR_COUNT (MLXSW_HWMON_TEMP_SENSOR_MAX_COUNT * 4 + \
@@ -30,6 +32,7 @@ struct mlxsw_hwmon {
3032
struct attribute *attrs[MLXSW_HWMON_ATTR_COUNT + 1];
3133
struct mlxsw_hwmon_attr hwmon_attrs[MLXSW_HWMON_ATTR_COUNT];
3234
unsigned int attrs_count;
35+
u8 sensor_count;
3336
};
3437

3538
static ssize_t mlxsw_hwmon_temp_show(struct device *dev,
@@ -188,13 +191,147 @@ static ssize_t mlxsw_hwmon_pwm_store(struct device *dev,
188191
return len;
189192
}
190193

194+
static ssize_t mlxsw_hwmon_module_temp_show(struct device *dev,
195+
struct device_attribute *attr,
196+
char *buf)
197+
{
198+
struct mlxsw_hwmon_attr *mlwsw_hwmon_attr =
199+
container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
200+
struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
201+
char mtbr_pl[MLXSW_REG_MTBR_LEN] = {0};
202+
u16 temp;
203+
u8 module;
204+
int err;
205+
206+
module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count;
207+
mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module,
208+
1);
209+
err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtbr), mtbr_pl);
210+
if (err) {
211+
dev_err(dev, "Failed to query module temprature sensor\n");
212+
return err;
213+
}
214+
215+
mlxsw_reg_mtbr_temp_unpack(mtbr_pl, 0, &temp, NULL);
216+
/* Update status and temperature cache. */
217+
switch (temp) {
218+
case MLXSW_REG_MTBR_NO_CONN: /* fall-through */
219+
case MLXSW_REG_MTBR_NO_TEMP_SENS: /* fall-through */
220+
case MLXSW_REG_MTBR_INDEX_NA:
221+
temp = 0;
222+
break;
223+
case MLXSW_REG_MTBR_BAD_SENS_INFO:
224+
/* Untrusted cable is connected. Reading temperature from its
225+
* sensor is faulty.
226+
*/
227+
temp = 0;
228+
break;
229+
default:
230+
temp = MLXSW_REG_MTMP_TEMP_TO_MC(temp);
231+
break;
232+
}
233+
234+
return sprintf(buf, "%u\n", temp);
235+
}
236+
237+
static ssize_t mlxsw_hwmon_module_temp_fault_show(struct device *dev,
238+
struct device_attribute *attr,
239+
char *buf)
240+
{
241+
struct mlxsw_hwmon_attr *mlwsw_hwmon_attr =
242+
container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
243+
struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
244+
char mtbr_pl[MLXSW_REG_MTBR_LEN] = {0};
245+
u8 module, fault;
246+
u16 temp;
247+
int err;
248+
249+
module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count;
250+
mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module,
251+
1);
252+
err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtbr), mtbr_pl);
253+
if (err) {
254+
dev_err(dev, "Failed to query module temprature sensor\n");
255+
return err;
256+
}
257+
258+
mlxsw_reg_mtbr_temp_unpack(mtbr_pl, 0, &temp, NULL);
259+
260+
/* Update status and temperature cache. */
261+
switch (temp) {
262+
case MLXSW_REG_MTBR_BAD_SENS_INFO:
263+
/* Untrusted cable is connected. Reading temperature from its
264+
* sensor is faulty.
265+
*/
266+
fault = 1;
267+
break;
268+
case MLXSW_REG_MTBR_NO_CONN: /* fall-through */
269+
case MLXSW_REG_MTBR_NO_TEMP_SENS: /* fall-through */
270+
case MLXSW_REG_MTBR_INDEX_NA:
271+
default:
272+
fault = 0;
273+
break;
274+
}
275+
276+
return sprintf(buf, "%u\n", fault);
277+
}
278+
279+
static ssize_t
280+
mlxsw_hwmon_module_temp_critical_show(struct device *dev,
281+
struct device_attribute *attr, char *buf)
282+
{
283+
struct mlxsw_hwmon_attr *mlwsw_hwmon_attr =
284+
container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
285+
struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
286+
int temp;
287+
u8 module;
288+
int err;
289+
290+
module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count;
291+
err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, module,
292+
SFP_TEMP_HIGH_WARN, &temp);
293+
if (err) {
294+
dev_err(dev, "Failed to query module temprature thresholds\n");
295+
return err;
296+
}
297+
298+
return sprintf(buf, "%u\n", temp);
299+
}
300+
301+
static ssize_t
302+
mlxsw_hwmon_module_temp_emergency_show(struct device *dev,
303+
struct device_attribute *attr,
304+
char *buf)
305+
{
306+
struct mlxsw_hwmon_attr *mlwsw_hwmon_attr =
307+
container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
308+
struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
309+
u8 module;
310+
int temp;
311+
int err;
312+
313+
module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count;
314+
err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, module,
315+
SFP_TEMP_HIGH_ALARM, &temp);
316+
if (err) {
317+
dev_err(dev, "Failed to query module temprature thresholds\n");
318+
return err;
319+
}
320+
321+
return sprintf(buf, "%u\n", temp);
322+
}
323+
191324
enum mlxsw_hwmon_attr_type {
192325
MLXSW_HWMON_ATTR_TYPE_TEMP,
193326
MLXSW_HWMON_ATTR_TYPE_TEMP_MAX,
194327
MLXSW_HWMON_ATTR_TYPE_TEMP_RST,
195328
MLXSW_HWMON_ATTR_TYPE_FAN_RPM,
196329
MLXSW_HWMON_ATTR_TYPE_FAN_FAULT,
197330
MLXSW_HWMON_ATTR_TYPE_PWM,
331+
MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE,
332+
MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_FAULT,
333+
MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_CRIT,
334+
MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_EMERG,
198335
};
199336

200337
static void mlxsw_hwmon_attr_add(struct mlxsw_hwmon *mlxsw_hwmon,
@@ -244,6 +381,33 @@ static void mlxsw_hwmon_attr_add(struct mlxsw_hwmon *mlxsw_hwmon,
244381
snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
245382
"pwm%u", num + 1);
246383
break;
384+
case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE:
385+
mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_module_temp_show;
386+
mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
387+
snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
388+
"temp%u_input", num + 1);
389+
break;
390+
case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_FAULT:
391+
mlxsw_hwmon_attr->dev_attr.show =
392+
mlxsw_hwmon_module_temp_fault_show;
393+
mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
394+
snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
395+
"temp%u_fault", num + 1);
396+
break;
397+
case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_CRIT:
398+
mlxsw_hwmon_attr->dev_attr.show =
399+
mlxsw_hwmon_module_temp_critical_show;
400+
mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
401+
snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
402+
"temp%u_crit", num + 1);
403+
break;
404+
case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_EMERG:
405+
mlxsw_hwmon_attr->dev_attr.show =
406+
mlxsw_hwmon_module_temp_emergency_show;
407+
mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
408+
snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
409+
"temp%u_emergency", num + 1);
410+
break;
247411
default:
248412
WARN_ON(1);
249413
}
@@ -261,7 +425,6 @@ static int mlxsw_hwmon_temp_init(struct mlxsw_hwmon *mlxsw_hwmon)
261425
{
262426
char mtcap_pl[MLXSW_REG_MTCAP_LEN] = {0};
263427
char mtmp_pl[MLXSW_REG_MTMP_LEN];
264-
u8 sensor_count;
265428
int i;
266429
int err;
267430

@@ -270,8 +433,8 @@ static int mlxsw_hwmon_temp_init(struct mlxsw_hwmon *mlxsw_hwmon)
270433
dev_err(mlxsw_hwmon->bus_info->dev, "Failed to get number of temp sensors\n");
271434
return err;
272435
}
273-
sensor_count = mlxsw_reg_mtcap_sensor_count_get(mtcap_pl);
274-
for (i = 0; i < sensor_count; i++) {
436+
mlxsw_hwmon->sensor_count = mlxsw_reg_mtcap_sensor_count_get(mtcap_pl);
437+
for (i = 0; i < mlxsw_hwmon->sensor_count; i++) {
275438
mlxsw_reg_mtmp_pack(mtmp_pl, i, true, true);
276439
err = mlxsw_reg_write(mlxsw_hwmon->core,
277440
MLXSW_REG(mtmp), mtmp_pl);
@@ -327,6 +490,50 @@ static int mlxsw_hwmon_fans_init(struct mlxsw_hwmon *mlxsw_hwmon)
327490
return 0;
328491
}
329492

493+
static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon)
494+
{
495+
unsigned int module_count = mlxsw_core_max_ports(mlxsw_hwmon->core);
496+
char pmlp_pl[MLXSW_REG_PMLP_LEN] = {0};
497+
int i, index;
498+
u8 width;
499+
int err;
500+
501+
/* Add extra attributes for module temperature. Sensor index is
502+
* assigned to sensor_count value, while all indexed before
503+
* sensor_count are already utilized by the sensors connected through
504+
* mtmp register by mlxsw_hwmon_temp_init().
505+
*/
506+
index = mlxsw_hwmon->sensor_count;
507+
for (i = 1; i < module_count; i++) {
508+
mlxsw_reg_pmlp_pack(pmlp_pl, i);
509+
err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(pmlp),
510+
pmlp_pl);
511+
if (err) {
512+
dev_err(mlxsw_hwmon->bus_info->dev, "Failed to read module index %d\n",
513+
i);
514+
return err;
515+
}
516+
width = mlxsw_reg_pmlp_width_get(pmlp_pl);
517+
if (!width)
518+
continue;
519+
mlxsw_hwmon_attr_add(mlxsw_hwmon,
520+
MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE, index,
521+
index);
522+
mlxsw_hwmon_attr_add(mlxsw_hwmon,
523+
MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_FAULT,
524+
index, index);
525+
mlxsw_hwmon_attr_add(mlxsw_hwmon,
526+
MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_CRIT,
527+
index, index);
528+
mlxsw_hwmon_attr_add(mlxsw_hwmon,
529+
MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_EMERG,
530+
index, index);
531+
index++;
532+
}
533+
534+
return 0;
535+
}
536+
330537
int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core,
331538
const struct mlxsw_bus_info *mlxsw_bus_info,
332539
struct mlxsw_hwmon **p_hwmon)
@@ -349,6 +556,10 @@ int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core,
349556
if (err)
350557
goto err_fans_init;
351558

559+
err = mlxsw_hwmon_module_init(mlxsw_hwmon);
560+
if (err)
561+
goto err_temp_module_init;
562+
352563
mlxsw_hwmon->groups[0] = &mlxsw_hwmon->group;
353564
mlxsw_hwmon->group.attrs = mlxsw_hwmon->attrs;
354565

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

367578
err_hwmon_register:
579+
err_temp_module_init:
368580
err_fans_init:
369581
err_temp_init:
370582
kfree(mlxsw_hwmon);

0 commit comments

Comments
 (0)