Skip to content

Commit 4da71a7

Browse files
konradknitterPaolo Abeni
authored andcommitted
ice: read internal temperature sensor
Since 4.30 firmware exposes internal thermal sensor reading via admin queue commands. Expose those readouts via hwmon API when supported. Datasheet: Get Sensor Reading Command (Opcode: 0x0632) +--------------------+--------+--------------------+-------------------------+ | Name | Bytes | Value | Remarks | +--------------------+--------+--------------------+-------------------------+ | Flags | 1-0 | | | | Opcode | 2-3 | 0x0632 | Command opcode | | Datalen | 4-5 | 0 | No external buffer. | | Return value | 6-7 | | Return value. | | Cookie High | 8-11 | Cookie | | | Cookie Low | 12-15 | Cookie | | | Sensor | 16 | | 0x00: Internal temp | | | | | 0x01-0xFF: Reserved. | | Format | 17 | Requested response | Only 0x00 is supported. | | | | format | 0x01-0xFF: Reserved. | | Reserved | 18-23 | | | | Data Address high | 24-27 | Response buffer | | | | | address | | | Data Address low | 28-31 | Response buffer | | | | | address | | +--------------------+--------+--------------------+-------------------------+ Get Sensor Reading Response (Opcode: 0x0632) +--------------------+--------+--------------------+-------------------------+ | Name | Bytes | Value | Remarks | +--------------------+--------+--------------------+-------------------------+ | Flags | 1-0 | | | | Opcode | 2-3 | 0x0632 | Command opcode | | Datalen | 4-5 | 0 | No external buffer | | Return value | 6-7 | | Return value. | | | | | EINVAL: Invalid | | | | | parameters | | | | | ENOENT: Unsupported | | | | | sensor | | | | | EIO: Sensor access | | | | | error | | Cookie High | 8-11 | Cookie | | | Cookie Low | 12-15 | Cookie | | | Sensor Reading | 16-23 | | Format of the reading | | | | | is dependent on request | | Data Address high | 24-27 | Response buffer | | | | | address | | | Data Address low | 28-31 | Response buffer | | | | | address | | +--------------------+--------+--------------------+-------------------------+ Sensor Reading for Sensor 0x00 (Internal Chip Temperature): +--------------------+--------+--------------------+-------------------------+ | Name | Bytes | Value | Remarks | +--------------------+--------+--------------------+-------------------------+ | Thermal Sensor | 0 | | Reading in degrees | | reading | | | Celsius. Signed int8 | | Warning High | 1 | | Warning High threshold | | threshold | | | in degrees Celsius. | | | | | Unsigned int8. | | | | | 0xFF when unsupported | | Critical High | 2 | | Critical High threshold | | threshold | | | in degrees Celsius. | | | | | Unsigned int8. | | | | | 0xFF when unsupported | | Fatal High | 3 | | Fatal High threshold | | threshold | | | in degrees Celsius. | | | | | Unsigned int8. | | | | | 0xFF when unsupported | | Reserved | 4-7 | | | +--------------------+--------+--------------------+-------------------------+ Driver provides current reading from HW as well as device specific thresholds for thermal alarm (Warning, Critical, Fatal) events. $ sensors Output ========================================================= ice-pci-b100 Adapter: PCI adapter temp1: +62.0°C (high = +95.0°C, crit = +105.0°C) (emerg = +115.0°C) Tested on Intel Corporation Ethernet Controller E810-C for SFP Co-developed-by: Marcin Domagala <[email protected]> Signed-off-by: Marcin Domagala <[email protected]> Co-developed-by: Eric Joyner <[email protected]> Signed-off-by: Eric Joyner <[email protected]> Reviewed-by: Marcin Szycik <[email protected]> Reviewed-by: Przemek Kitszel <[email protected]> Signed-off-by: Konrad Knitter <[email protected]> Tested-by: Pucha Himasekhar Reddy <[email protected]> (A Contingent worker at Intel) Signed-off-by: Tony Nguyen <[email protected]> Signed-off-by: Paolo Abeni <[email protected]>
1 parent 4aee43f commit 4da71a7

File tree

10 files changed

+249
-1
lines changed

10 files changed

+249
-1
lines changed

drivers/net/ethernet/intel/Kconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,17 @@ config ICE
299299
To compile this driver as a module, choose M here. The module
300300
will be called ice.
301301

302+
config ICE_HWMON
303+
bool "Intel(R) Ethernet Connection E800 Series Support HWMON support"
304+
default y
305+
depends on ICE && HWMON && !(ICE=y && HWMON=m)
306+
help
307+
Say Y if you want to expose thermal sensor data on Intel devices.
308+
309+
Some of our devices contain internal thermal sensors.
310+
This data is available via the hwmon sysfs interface and exposes
311+
the onboard sensors.
312+
302313
config ICE_SWITCHDEV
303314
bool "Switchdev Support"
304315
default y

drivers/net/ethernet/intel/ice/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,4 @@ ice-$(CONFIG_RFS_ACCEL) += ice_arfs.o
4949
ice-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
5050
ice-$(CONFIG_ICE_SWITCHDEV) += ice_eswitch.o ice_eswitch_br.o
5151
ice-$(CONFIG_GNSS) += ice_gnss.o
52+
ice-$(CONFIG_ICE_HWMON) += ice_hwmon.o

drivers/net/ethernet/intel/ice/ice.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,7 @@ struct ice_pf {
655655
#define ICE_MAX_VF_AGG_NODES 32
656656
struct ice_agg_node vf_agg_node[ICE_MAX_VF_AGG_NODES];
657657
struct ice_dplls dplls;
658+
struct device *hwmon_dev;
658659
};
659660

660661
extern struct workqueue_struct *ice_lag_wq;

drivers/net/ethernet/intel/ice/ice_adminq_cmd.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ struct ice_aqc_list_caps_elem {
117117
#define ICE_AQC_CAPS_NET_VER 0x004C
118118
#define ICE_AQC_CAPS_PENDING_NET_VER 0x004D
119119
#define ICE_AQC_CAPS_RDMA 0x0051
120+
#define ICE_AQC_CAPS_SENSOR_READING 0x0067
120121
#define ICE_AQC_CAPS_PCIE_RESET_AVOIDANCE 0x0076
121122
#define ICE_AQC_CAPS_POST_UPDATE_RESET_RESTRICT 0x0077
122123
#define ICE_AQC_CAPS_NVM_MGMT 0x0080
@@ -1413,6 +1414,30 @@ struct ice_aqc_get_phy_rec_clk_out {
14131414
__le16 node_handle;
14141415
};
14151416

1417+
/* Get sensor reading (direct 0x0632) */
1418+
struct ice_aqc_get_sensor_reading {
1419+
u8 sensor;
1420+
u8 format;
1421+
u8 reserved[6];
1422+
__le32 addr_high;
1423+
__le32 addr_low;
1424+
};
1425+
1426+
/* Get sensor reading response (direct 0x0632) */
1427+
struct ice_aqc_get_sensor_reading_resp {
1428+
union {
1429+
u8 raw[8];
1430+
/* Output data for sensor 0x00, format 0x00 */
1431+
struct _packed {
1432+
s8 temp;
1433+
u8 temp_warning_threshold;
1434+
u8 temp_critical_threshold;
1435+
u8 temp_fatal_threshold;
1436+
u8 reserved[4];
1437+
} s0f0;
1438+
} data;
1439+
};
1440+
14161441
struct ice_aqc_link_topo_params {
14171442
u8 lport_num;
14181443
u8 lport_num_valid;
@@ -2443,6 +2468,8 @@ struct ice_aq_desc {
24432468
struct ice_aqc_restart_an restart_an;
24442469
struct ice_aqc_set_phy_rec_clk_out set_phy_rec_clk_out;
24452470
struct ice_aqc_get_phy_rec_clk_out get_phy_rec_clk_out;
2471+
struct ice_aqc_get_sensor_reading get_sensor_reading;
2472+
struct ice_aqc_get_sensor_reading_resp get_sensor_reading_resp;
24462473
struct ice_aqc_gpio read_write_gpio;
24472474
struct ice_aqc_sff_eeprom read_write_sff_param;
24482475
struct ice_aqc_set_port_id_led set_port_id_led;
@@ -2618,6 +2645,7 @@ enum ice_adminq_opc {
26182645
ice_aqc_opc_set_mac_lb = 0x0620,
26192646
ice_aqc_opc_set_phy_rec_clk_out = 0x0630,
26202647
ice_aqc_opc_get_phy_rec_clk_out = 0x0631,
2648+
ice_aqc_opc_get_sensor_reading = 0x0632,
26212649
ice_aqc_opc_get_link_topo = 0x06E0,
26222650
ice_aqc_opc_read_i2c = 0x06E2,
26232651
ice_aqc_opc_write_i2c = 0x06E3,

drivers/net/ethernet/intel/ice/ice_common.c

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2710,6 +2710,26 @@ ice_parse_fdir_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p,
27102710
dev_p->num_flow_director_fltr);
27112711
}
27122712

2713+
/**
2714+
* ice_parse_sensor_reading_cap - Parse ICE_AQC_CAPS_SENSOR_READING cap
2715+
* @hw: pointer to the HW struct
2716+
* @dev_p: pointer to device capabilities structure
2717+
* @cap: capability element to parse
2718+
*
2719+
* Parse ICE_AQC_CAPS_SENSOR_READING for device capability for reading
2720+
* enabled sensors.
2721+
*/
2722+
static void
2723+
ice_parse_sensor_reading_cap(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p,
2724+
struct ice_aqc_list_caps_elem *cap)
2725+
{
2726+
dev_p->supported_sensors = le32_to_cpu(cap->number);
2727+
2728+
ice_debug(hw, ICE_DBG_INIT,
2729+
"dev caps: supported sensors (bitmap) = 0x%x\n",
2730+
dev_p->supported_sensors);
2731+
}
2732+
27132733
/**
27142734
* ice_parse_dev_caps - Parse device capabilities
27152735
* @hw: pointer to the HW struct
@@ -2755,9 +2775,12 @@ ice_parse_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p,
27552775
case ICE_AQC_CAPS_1588:
27562776
ice_parse_1588_dev_caps(hw, dev_p, &cap_resp[i]);
27572777
break;
2758-
case ICE_AQC_CAPS_FD:
2778+
case ICE_AQC_CAPS_FD:
27592779
ice_parse_fdir_dev_caps(hw, dev_p, &cap_resp[i]);
27602780
break;
2781+
case ICE_AQC_CAPS_SENSOR_READING:
2782+
ice_parse_sensor_reading_cap(hw, dev_p, &cap_resp[i]);
2783+
break;
27612784
default:
27622785
/* Don't list common capabilities as unknown */
27632786
if (!found)
@@ -5540,6 +5563,35 @@ ice_aq_get_phy_rec_clk_out(struct ice_hw *hw, u8 *phy_output, u8 *port_num,
55405563
return status;
55415564
}
55425565

5566+
/**
5567+
* ice_aq_get_sensor_reading
5568+
* @hw: pointer to the HW struct
5569+
* @data: pointer to data to be read from the sensor
5570+
*
5571+
* Get sensor reading (0x0632)
5572+
*/
5573+
int ice_aq_get_sensor_reading(struct ice_hw *hw,
5574+
struct ice_aqc_get_sensor_reading_resp *data)
5575+
{
5576+
struct ice_aqc_get_sensor_reading *cmd;
5577+
struct ice_aq_desc desc;
5578+
int status;
5579+
5580+
ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_sensor_reading);
5581+
cmd = &desc.params.get_sensor_reading;
5582+
#define ICE_INTERNAL_TEMP_SENSOR_FORMAT 0
5583+
#define ICE_INTERNAL_TEMP_SENSOR 0
5584+
cmd->sensor = ICE_INTERNAL_TEMP_SENSOR;
5585+
cmd->format = ICE_INTERNAL_TEMP_SENSOR_FORMAT;
5586+
5587+
status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
5588+
if (!status)
5589+
memcpy(data, &desc.params.get_sensor_reading_resp,
5590+
sizeof(*data));
5591+
5592+
return status;
5593+
}
5594+
55435595
/**
55445596
* ice_replay_pre_init - replay pre initialization
55455597
* @hw: pointer to the HW struct

drivers/net/ethernet/intel/ice/ice_common.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,8 @@ ice_aq_set_phy_rec_clk_out(struct ice_hw *hw, u8 phy_output, bool enable,
241241
int
242242
ice_aq_get_phy_rec_clk_out(struct ice_hw *hw, u8 *phy_output, u8 *port_num,
243243
u8 *flags, u16 *node_handle);
244+
int ice_aq_get_sensor_reading(struct ice_hw *hw,
245+
struct ice_aqc_get_sensor_reading_resp *data);
244246
void
245247
ice_stat_update40(struct ice_hw *hw, u32 reg, bool prev_stat_loaded,
246248
u64 *prev_stat, u64 *cur_stat);
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright (C) 2023, Intel Corporation. */
3+
4+
#include "ice.h"
5+
#include "ice_hwmon.h"
6+
#include "ice_adminq_cmd.h"
7+
8+
#include <linux/hwmon.h>
9+
10+
#define TEMP_FROM_REG(reg) ((reg) * 1000)
11+
12+
static const struct hwmon_channel_info *ice_hwmon_info[] = {
13+
HWMON_CHANNEL_INFO(temp,
14+
HWMON_T_INPUT | HWMON_T_MAX |
15+
HWMON_T_CRIT | HWMON_T_EMERGENCY),
16+
NULL
17+
};
18+
19+
static int ice_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
20+
u32 attr, int channel, long *val)
21+
{
22+
struct ice_aqc_get_sensor_reading_resp resp;
23+
struct ice_pf *pf = dev_get_drvdata(dev);
24+
int ret;
25+
26+
if (type != hwmon_temp)
27+
return -EOPNOTSUPP;
28+
29+
ret = ice_aq_get_sensor_reading(&pf->hw, &resp);
30+
if (ret) {
31+
dev_warn_ratelimited(dev,
32+
"%s HW read failure (%d)\n",
33+
__func__,
34+
ret);
35+
return ret;
36+
}
37+
38+
switch (attr) {
39+
case hwmon_temp_input:
40+
*val = TEMP_FROM_REG(resp.data.s0f0.temp);
41+
break;
42+
case hwmon_temp_max:
43+
*val = TEMP_FROM_REG(resp.data.s0f0.temp_warning_threshold);
44+
break;
45+
case hwmon_temp_crit:
46+
*val = TEMP_FROM_REG(resp.data.s0f0.temp_critical_threshold);
47+
break;
48+
case hwmon_temp_emergency:
49+
*val = TEMP_FROM_REG(resp.data.s0f0.temp_fatal_threshold);
50+
break;
51+
default:
52+
dev_dbg(dev, "%s unsupported attribute (%d)\n",
53+
__func__, attr);
54+
return -EOPNOTSUPP;
55+
}
56+
57+
return 0;
58+
}
59+
60+
static umode_t ice_hwmon_is_visible(const void *data,
61+
enum hwmon_sensor_types type, u32 attr,
62+
int channel)
63+
{
64+
if (type != hwmon_temp)
65+
return 0;
66+
67+
switch (attr) {
68+
case hwmon_temp_input:
69+
case hwmon_temp_crit:
70+
case hwmon_temp_max:
71+
case hwmon_temp_emergency:
72+
return 0444;
73+
}
74+
75+
return 0;
76+
}
77+
78+
static const struct hwmon_ops ice_hwmon_ops = {
79+
.is_visible = ice_hwmon_is_visible,
80+
.read = ice_hwmon_read
81+
};
82+
83+
static const struct hwmon_chip_info ice_chip_info = {
84+
.ops = &ice_hwmon_ops,
85+
.info = ice_hwmon_info
86+
};
87+
88+
static bool ice_is_internal_reading_supported(struct ice_pf *pf)
89+
{
90+
/* Only the first PF will report temperature for a chip.
91+
* Note that internal temp reading is not supported
92+
* for older FW (< v4.30).
93+
*/
94+
if (pf->hw.pf_id)
95+
return false;
96+
97+
unsigned long sensors = pf->hw.dev_caps.supported_sensors;
98+
99+
return _test_bit(ICE_SENSOR_SUPPORT_E810_INT_TEMP_BIT, &sensors);
100+
};
101+
102+
void ice_hwmon_init(struct ice_pf *pf)
103+
{
104+
struct device *dev = ice_pf_to_dev(pf);
105+
struct device *hdev;
106+
107+
if (!ice_is_internal_reading_supported(pf))
108+
return;
109+
110+
hdev = hwmon_device_register_with_info(dev, "ice", pf, &ice_chip_info,
111+
NULL);
112+
if (IS_ERR(hdev)) {
113+
dev_warn(dev,
114+
"hwmon_device_register_with_info returns error (%ld)",
115+
PTR_ERR(hdev));
116+
return;
117+
}
118+
pf->hwmon_dev = hdev;
119+
}
120+
121+
void ice_hwmon_exit(struct ice_pf *pf)
122+
{
123+
if (!pf->hwmon_dev)
124+
return;
125+
hwmon_device_unregister(pf->hwmon_dev);
126+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/* Copyright (C) 2023, Intel Corporation. */
3+
4+
#ifndef _ICE_HWMON_H_
5+
#define _ICE_HWMON_H_
6+
7+
#ifdef CONFIG_ICE_HWMON
8+
void ice_hwmon_init(struct ice_pf *pf);
9+
void ice_hwmon_exit(struct ice_pf *pf);
10+
#else /* CONFIG_ICE_HWMON */
11+
static inline void ice_hwmon_init(struct ice_pf *pf) { }
12+
static inline void ice_hwmon_exit(struct ice_pf *pf) { }
13+
#endif /* CONFIG_ICE_HWMON */
14+
15+
#endif /* _ICE_HWMON_H_ */

drivers/net/ethernet/intel/ice/ice_main.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "ice_dcb_lib.h"
1515
#include "ice_dcb_nl.h"
1616
#include "ice_devlink.h"
17+
#include "ice_hwmon.h"
1718
/* Including ice_trace.h with CREATE_TRACE_POINTS defined will generate the
1819
* ice tracepoint functions. This must be done exactly once across the
1920
* ice driver.
@@ -4687,6 +4688,8 @@ static void ice_init_features(struct ice_pf *pf)
46874688

46884689
if (ice_init_lag(pf))
46894690
dev_warn(dev, "Failed to init link aggregation support\n");
4691+
4692+
ice_hwmon_init(pf);
46904693
}
46914694

46924695
static void ice_deinit_features(struct ice_pf *pf)
@@ -5212,6 +5215,8 @@ static void ice_remove(struct pci_dev *pdev)
52125215
ice_free_vfs(pf);
52135216
}
52145217

5218+
ice_hwmon_exit(pf);
5219+
52155220
ice_service_task_stop(pf);
52165221
ice_aq_cancel_waiting_tasks(pf);
52175222
set_bit(ICE_DOWN, pf->state);

drivers/net/ethernet/intel/ice/ice_type.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,8 @@ struct ice_hw_func_caps {
377377
struct ice_ts_func_info ts_func_info;
378378
};
379379

380+
#define ICE_SENSOR_SUPPORT_E810_INT_TEMP_BIT 0
381+
380382
/* Device wide capabilities */
381383
struct ice_hw_dev_caps {
382384
struct ice_hw_common_caps common_cap;
@@ -385,6 +387,11 @@ struct ice_hw_dev_caps {
385387
u32 num_flow_director_fltr; /* Number of FD filters available */
386388
struct ice_ts_dev_info ts_dev_info;
387389
u32 num_funcs;
390+
/* bitmap of supported sensors
391+
* bit 0 - internal temperature sensor
392+
* bit 31:1 - Reserved
393+
*/
394+
u32 supported_sensors;
388395
};
389396

390397
/* MAC info */

0 commit comments

Comments
 (0)