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
12static 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
19static 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
60static 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
78static const struct hwmon_ops ice_hwmon_ops = {
79	.is_visible = ice_hwmon_is_visible,
80	.read = ice_hwmon_read
81};
82
83static const struct hwmon_chip_info ice_chip_info = {
84	.ops = &ice_hwmon_ops,
85	.info = ice_hwmon_info
86};
87
88static 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
102void 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
121void ice_hwmon_exit(struct ice_pf *pf)
122{
123	if (!pf->hwmon_dev)
124		return;
125	hwmon_device_unregister(pf->hwmon_dev);
126}
127