Commit 1f507e80 authored by Adham Faris's avatar Adham Faris Committed by Jakub Kicinski

net/mlx5: Expose NIC temperature via hardware monitoring kernel API

Expose NIC temperature by implementing hwmon kernel API, which turns
current thermal zone kernel API to redundant.

For each one of the supported and exposed thermal diode sensors, expose
the following attributes:
1) Input temperature.
2) Highest temperature.
3) Temperature label:
   Depends on the firmware capability, if firmware doesn't support
   sensors naming, the fallback naming convention would be: "sensorX",
   where X is the HW spec (MTMP register) sensor index.
4) Temperature critical max value:
   refers to the high threshold of Warning Event. Will be exposed as
   `tempY_crit` hwmon attribute (RO attribute). For example for
   ConnectX5 HCA's this temperature value will be 105 Celsius, 10
   degrees lower than the HW shutdown temperature).
5) Temperature reset history: resets highest temperature.

For example, for dualport ConnectX5 NIC with a single IC thermal diode
sensor will have 2 hwmon directories (one for each PCI function)
under "/sys/class/hwmon/hwmon[X,Y]".

Listing one of the directories above (hwmonX/Y) generates the
corresponding output below:

$ grep -H -d skip . /sys/class/hwmon/hwmon0/*

Output
=======================================================================
/sys/class/hwmon/hwmon0/name:mlx5
/sys/class/hwmon/hwmon0/temp1_crit:105000
/sys/class/hwmon/hwmon0/temp1_highest:48000
/sys/class/hwmon/hwmon0/temp1_input:46000
/sys/class/hwmon/hwmon0/temp1_label:asic
grep: /sys/class/hwmon/hwmon0/temp1_reset_history: Permission denied

In addition, displaying the sensors data via lm_sensors generates the
corresponding output below:

$ sensors

Output
=======================================================================
mlx5-pci-0800
Adapter: PCI adapter
asic:         +46.0°C  (crit = +105.0°C, highest = +48.0°C)

mlx5-pci-0801
Adapter: PCI adapter
asic:         +46.0°C  (crit = +105.0°C, highest = +48.0°C)

CC: Jean Delvare <jdelvare@suse.com>
Signed-off-by: default avatarAdham Faris <afaris@nvidia.com>
Reviewed-by: default avatarTariq Toukan <tariqt@nvidia.com>
Reviewed-by: default avatarGal Pressman <gal@nvidia.com>
Signed-off-by: default avatarSaeed Mahameed <saeedm@nvidia.com>
Acked-by: default avatarGuenter Roeck <linux@roeck-us.net>
Reviewed-by: default avatarSimon Horman <horms@kernel.org>
Link: https://lore.kernel.org/r/20230807180507.22984-3-saeed@kernel.orgSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 383a4de3
......@@ -12,6 +12,7 @@ config MLX5_CORE
depends on MLXFW || !MLXFW
depends on PTP_1588_CLOCK_OPTIONAL
depends on PCI_HYPERV_INTERFACE || !PCI_HYPERV_INTERFACE
depends on HWMON || !HWMON
help
Core driver for low level functionality of the ConnectX-4 and
Connect-IB cards by Mellanox Technologies.
......
......@@ -82,7 +82,7 @@ endif
mlx5_core-$(CONFIG_MLX5_BRIDGE) += esw/bridge.o esw/bridge_mcast.o esw/bridge_debugfs.o \
en/rep/bridge.o
mlx5_core-$(CONFIG_THERMAL) += thermal.o
mlx5_core-$(CONFIG_HWMON) += hwmon.o
mlx5_core-$(CONFIG_MLX5_MPFS) += lib/mpfs.o
mlx5_core-$(CONFIG_VXLAN) += lib/vxlan.o
mlx5_core-$(CONFIG_PTP_1588_CLOCK) += lib/clock.o
......
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
* Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved
*/
#ifndef __MLX5_HWMON_H__
#define __MLX5_HWMON_H__
#include <linux/mlx5/driver.h>
#if IS_ENABLED(CONFIG_HWMON)
int mlx5_hwmon_dev_register(struct mlx5_core_dev *mdev);
void mlx5_hwmon_dev_unregister(struct mlx5_core_dev *mdev);
#else
static inline int mlx5_hwmon_dev_register(struct mlx5_core_dev *mdev)
{
return 0;
}
static inline void mlx5_hwmon_dev_unregister(struct mlx5_core_dev *mdev) {}
#endif
#endif /* __MLX5_HWMON_H__ */
......@@ -49,7 +49,6 @@
#include <linux/version.h>
#include <net/devlink.h>
#include "mlx5_core.h"
#include "thermal.h"
#include "lib/eq.h"
#include "fs_core.h"
#include "lib/mpfs.h"
......@@ -73,6 +72,7 @@
#include "sf/dev/dev.h"
#include "sf/sf.h"
#include "mlx5_irq.h"
#include "hwmon.h"
MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>");
MODULE_DESCRIPTION("Mellanox 5th generation network adapters (ConnectX series) core driver");
......@@ -1930,9 +1930,9 @@ static int probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
if (err)
dev_err(&pdev->dev, "mlx5_crdump_enable failed with error code %d\n", err);
err = mlx5_thermal_init(dev);
err = mlx5_hwmon_dev_register(dev);
if (err)
dev_err(&pdev->dev, "mlx5_thermal_init failed with error code %d\n", err);
mlx5_core_err(dev, "mlx5_hwmon_dev_register failed with error code %d\n", err);
pci_save_state(pdev);
devlink_register(devlink);
......@@ -1964,7 +1964,7 @@ static void remove_one(struct pci_dev *pdev)
mlx5_drain_health_wq(dev);
devlink_unregister(devlink);
mlx5_sriov_disable(pdev, false);
mlx5_thermal_uninit(dev);
mlx5_hwmon_dev_unregister(dev);
mlx5_crdump_disable(dev);
mlx5_uninit_one(dev);
mlx5_pci_close(dev);
......
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
// Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES.
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/device.h>
#include <linux/thermal.h>
#include <linux/err.h>
#include <linux/mlx5/driver.h>
#include "mlx5_core.h"
#include "thermal.h"
#define MLX5_THERMAL_POLL_INT_MSEC 1000
#define MLX5_THERMAL_NUM_TRIPS 0
#define MLX5_THERMAL_ASIC_SENSOR_INDEX 0
/* Bit string indicating the writeablility of trip points if any */
#define MLX5_THERMAL_TRIP_MASK (BIT(MLX5_THERMAL_NUM_TRIPS) - 1)
struct mlx5_thermal {
struct mlx5_core_dev *mdev;
struct thermal_zone_device *tzdev;
};
static int mlx5_thermal_get_mtmp_temp(struct mlx5_core_dev *mdev, u32 id, int *p_temp)
{
u32 mtmp_out[MLX5_ST_SZ_DW(mtmp_reg)] = {};
u32 mtmp_in[MLX5_ST_SZ_DW(mtmp_reg)] = {};
int err;
MLX5_SET(mtmp_reg, mtmp_in, sensor_index, id);
err = mlx5_core_access_reg(mdev, mtmp_in, sizeof(mtmp_in),
mtmp_out, sizeof(mtmp_out),
MLX5_REG_MTMP, 0, 0);
if (err)
return err;
*p_temp = MLX5_GET(mtmp_reg, mtmp_out, temperature);
return 0;
}
static int mlx5_thermal_get_temp(struct thermal_zone_device *tzdev,
int *p_temp)
{
struct mlx5_thermal *thermal = thermal_zone_device_priv(tzdev);
struct mlx5_core_dev *mdev = thermal->mdev;
int err;
err = mlx5_thermal_get_mtmp_temp(mdev, MLX5_THERMAL_ASIC_SENSOR_INDEX, p_temp);
if (err)
return err;
/* The unit of temp returned is in 0.125 C. The thermal
* framework expects the value in 0.001 C.
*/
*p_temp *= 125;
return 0;
}
static struct thermal_zone_device_ops mlx5_thermal_ops = {
.get_temp = mlx5_thermal_get_temp,
};
int mlx5_thermal_init(struct mlx5_core_dev *mdev)
{
char data[THERMAL_NAME_LENGTH];
struct mlx5_thermal *thermal;
int err;
if (!mlx5_core_is_pf(mdev) && !mlx5_core_is_ecpf(mdev))
return 0;
err = snprintf(data, sizeof(data), "mlx5_%s", dev_name(mdev->device));
if (err < 0 || err >= sizeof(data)) {
mlx5_core_err(mdev, "Failed to setup thermal zone name, %d\n", err);
return -EINVAL;
}
thermal = kzalloc(sizeof(*thermal), GFP_KERNEL);
if (!thermal)
return -ENOMEM;
thermal->mdev = mdev;
thermal->tzdev = thermal_zone_device_register_with_trips(data,
NULL,
MLX5_THERMAL_NUM_TRIPS,
MLX5_THERMAL_TRIP_MASK,
thermal,
&mlx5_thermal_ops,
NULL, 0, MLX5_THERMAL_POLL_INT_MSEC);
if (IS_ERR(thermal->tzdev)) {
err = PTR_ERR(thermal->tzdev);
mlx5_core_err(mdev, "Failed to register thermal zone device (%s) %d\n", data, err);
kfree(thermal);
return err;
}
mdev->thermal = thermal;
return 0;
}
void mlx5_thermal_uninit(struct mlx5_core_dev *mdev)
{
if (!mdev->thermal)
return;
thermal_zone_device_unregister(mdev->thermal->tzdev);
kfree(mdev->thermal);
}
/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
* Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES.
*/
#ifndef __MLX5_THERMAL_DRIVER_H
#define __MLX5_THERMAL_DRIVER_H
#if IS_ENABLED(CONFIG_THERMAL)
int mlx5_thermal_init(struct mlx5_core_dev *mdev);
void mlx5_thermal_uninit(struct mlx5_core_dev *mdev);
#else
static inline int mlx5_thermal_init(struct mlx5_core_dev *mdev)
{
mdev->thermal = NULL;
return 0;
}
static inline void mlx5_thermal_uninit(struct mlx5_core_dev *mdev) { }
#endif
#endif /* __MLX5_THERMAL_DRIVER_H */
......@@ -134,6 +134,7 @@ enum {
MLX5_REG_PCAM = 0x507f,
MLX5_REG_NODE_DESC = 0x6001,
MLX5_REG_HOST_ENDIANNESS = 0x7004,
MLX5_REG_MTCAP = 0x9009,
MLX5_REG_MTMP = 0x900A,
MLX5_REG_MCIA = 0x9014,
MLX5_REG_MFRL = 0x9028,
......@@ -805,7 +806,7 @@ struct mlx5_core_dev {
struct mlx5_rsc_dump *rsc_dump;
u32 vsc_addr;
struct mlx5_hv_vhca *hv_vhca;
struct mlx5_thermal *thermal;
struct mlx5_hwmon *hwmon;
u64 num_block_tc;
u64 num_block_ipsec;
};
......
......@@ -10196,7 +10196,9 @@ struct mlx5_ifc_mcam_access_reg_bits {
u8 mrtc[0x1];
u8 regs_44_to_32[0xd];
u8 regs_31_to_0[0x20];
u8 regs_31_to_10[0x16];
u8 mtmp[0x1];
u8 regs_8_to_0[0x9];
};
struct mlx5_ifc_mcam_access_reg_bits1 {
......@@ -10949,6 +10951,15 @@ struct mlx5_ifc_mrtc_reg_bits {
u8 time_l[0x20];
};
struct mlx5_ifc_mtcap_reg_bits {
u8 reserved_at_0[0x19];
u8 sensor_count[0x7];
u8 reserved_at_20[0x20];
u8 sensor_map[0x40];
};
struct mlx5_ifc_mtmp_reg_bits {
u8 reserved_at_0[0x14];
u8 sensor_index[0xc];
......@@ -11036,6 +11047,7 @@ union mlx5_ifc_ports_control_registers_document_bits {
struct mlx5_ifc_mfrl_reg_bits mfrl_reg;
struct mlx5_ifc_mtutc_reg_bits mtutc_reg;
struct mlx5_ifc_mrtc_reg_bits mrtc_reg;
struct mlx5_ifc_mtcap_reg_bits mtcap_reg;
struct mlx5_ifc_mtmp_reg_bits mtmp_reg;
u8 reserved_at_0[0x60e0];
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment