xref: /openbmc/linux/drivers/nvme/host/hwmon.c (revision 52deba0f02a98c150677a9c381cc1991a928bcff)
1400b6a7bSGuenter Roeck // SPDX-License-Identifier: GPL-2.0
2400b6a7bSGuenter Roeck /*
3400b6a7bSGuenter Roeck  * NVM Express hardware monitoring support
4400b6a7bSGuenter Roeck  * Copyright (c) 2019, Guenter Roeck
5400b6a7bSGuenter Roeck  */
6400b6a7bSGuenter Roeck 
7400b6a7bSGuenter Roeck #include <linux/hwmon.h>
8400b6a7bSGuenter Roeck #include <asm/unaligned.h>
9400b6a7bSGuenter Roeck 
10400b6a7bSGuenter Roeck #include "nvme.h"
11400b6a7bSGuenter Roeck 
12*52deba0fSAkinobu Mita /* These macros should be moved to linux/temperature.h */
13*52deba0fSAkinobu Mita #define MILLICELSIUS_TO_KELVIN(t) DIV_ROUND_CLOSEST((t) + 273150, 1000)
14*52deba0fSAkinobu Mita #define KELVIN_TO_MILLICELSIUS(t) ((t) * 1000L - 273150)
15*52deba0fSAkinobu Mita 
16400b6a7bSGuenter Roeck struct nvme_hwmon_data {
17400b6a7bSGuenter Roeck 	struct nvme_ctrl *ctrl;
18400b6a7bSGuenter Roeck 	struct nvme_smart_log log;
19400b6a7bSGuenter Roeck 	struct mutex read_lock;
20400b6a7bSGuenter Roeck };
21400b6a7bSGuenter Roeck 
22*52deba0fSAkinobu Mita static int nvme_get_temp_thresh(struct nvme_ctrl *ctrl, int sensor, bool under,
23*52deba0fSAkinobu Mita 				long *temp)
24*52deba0fSAkinobu Mita {
25*52deba0fSAkinobu Mita 	unsigned int threshold = sensor << NVME_TEMP_THRESH_SELECT_SHIFT;
26*52deba0fSAkinobu Mita 	u32 status;
27*52deba0fSAkinobu Mita 	int ret;
28*52deba0fSAkinobu Mita 
29*52deba0fSAkinobu Mita 	if (under)
30*52deba0fSAkinobu Mita 		threshold |= NVME_TEMP_THRESH_TYPE_UNDER;
31*52deba0fSAkinobu Mita 
32*52deba0fSAkinobu Mita 	ret = nvme_get_features(ctrl, NVME_FEAT_TEMP_THRESH, threshold, NULL, 0,
33*52deba0fSAkinobu Mita 				&status);
34*52deba0fSAkinobu Mita 	if (ret > 0)
35*52deba0fSAkinobu Mita 		return -EIO;
36*52deba0fSAkinobu Mita 	if (ret < 0)
37*52deba0fSAkinobu Mita 		return ret;
38*52deba0fSAkinobu Mita 	*temp = KELVIN_TO_MILLICELSIUS(status & NVME_TEMP_THRESH_MASK);
39*52deba0fSAkinobu Mita 
40*52deba0fSAkinobu Mita 	return 0;
41*52deba0fSAkinobu Mita }
42*52deba0fSAkinobu Mita 
43*52deba0fSAkinobu Mita static int nvme_set_temp_thresh(struct nvme_ctrl *ctrl, int sensor, bool under,
44*52deba0fSAkinobu Mita 				long temp)
45*52deba0fSAkinobu Mita {
46*52deba0fSAkinobu Mita 	unsigned int threshold = sensor << NVME_TEMP_THRESH_SELECT_SHIFT;
47*52deba0fSAkinobu Mita 	int ret;
48*52deba0fSAkinobu Mita 
49*52deba0fSAkinobu Mita 	temp = MILLICELSIUS_TO_KELVIN(temp);
50*52deba0fSAkinobu Mita 	threshold |= clamp_val(temp, 0, NVME_TEMP_THRESH_MASK);
51*52deba0fSAkinobu Mita 
52*52deba0fSAkinobu Mita 	if (under)
53*52deba0fSAkinobu Mita 		threshold |= NVME_TEMP_THRESH_TYPE_UNDER;
54*52deba0fSAkinobu Mita 
55*52deba0fSAkinobu Mita 	ret = nvme_set_features(ctrl, NVME_FEAT_TEMP_THRESH, threshold, NULL, 0,
56*52deba0fSAkinobu Mita 				NULL);
57*52deba0fSAkinobu Mita 	if (ret > 0)
58*52deba0fSAkinobu Mita 		return -EIO;
59*52deba0fSAkinobu Mita 
60*52deba0fSAkinobu Mita 	return ret;
61*52deba0fSAkinobu Mita }
62*52deba0fSAkinobu Mita 
63400b6a7bSGuenter Roeck static int nvme_hwmon_get_smart_log(struct nvme_hwmon_data *data)
64400b6a7bSGuenter Roeck {
65400b6a7bSGuenter Roeck 	int ret;
66400b6a7bSGuenter Roeck 
67400b6a7bSGuenter Roeck 	ret = nvme_get_log(data->ctrl, NVME_NSID_ALL, NVME_LOG_SMART, 0,
68400b6a7bSGuenter Roeck 			   &data->log, sizeof(data->log), 0);
69400b6a7bSGuenter Roeck 
70400b6a7bSGuenter Roeck 	return ret <= 0 ? ret : -EIO;
71400b6a7bSGuenter Roeck }
72400b6a7bSGuenter Roeck 
73400b6a7bSGuenter Roeck static int nvme_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
74400b6a7bSGuenter Roeck 			   u32 attr, int channel, long *val)
75400b6a7bSGuenter Roeck {
76400b6a7bSGuenter Roeck 	struct nvme_hwmon_data *data = dev_get_drvdata(dev);
77400b6a7bSGuenter Roeck 	struct nvme_smart_log *log = &data->log;
78400b6a7bSGuenter Roeck 	int temp;
79400b6a7bSGuenter Roeck 	int err;
80400b6a7bSGuenter Roeck 
81400b6a7bSGuenter Roeck 	/*
82400b6a7bSGuenter Roeck 	 * First handle attributes which don't require us to read
83400b6a7bSGuenter Roeck 	 * the smart log.
84400b6a7bSGuenter Roeck 	 */
85400b6a7bSGuenter Roeck 	switch (attr) {
86400b6a7bSGuenter Roeck 	case hwmon_temp_max:
87*52deba0fSAkinobu Mita 		return nvme_get_temp_thresh(data->ctrl, channel, false, val);
88*52deba0fSAkinobu Mita 	case hwmon_temp_min:
89*52deba0fSAkinobu Mita 		return nvme_get_temp_thresh(data->ctrl, channel, true, val);
90400b6a7bSGuenter Roeck 	case hwmon_temp_crit:
91*52deba0fSAkinobu Mita 		*val = KELVIN_TO_MILLICELSIUS(data->ctrl->cctemp);
92400b6a7bSGuenter Roeck 		return 0;
93400b6a7bSGuenter Roeck 	default:
94400b6a7bSGuenter Roeck 		break;
95400b6a7bSGuenter Roeck 	}
96400b6a7bSGuenter Roeck 
97400b6a7bSGuenter Roeck 	mutex_lock(&data->read_lock);
98400b6a7bSGuenter Roeck 	err = nvme_hwmon_get_smart_log(data);
99400b6a7bSGuenter Roeck 	if (err)
100400b6a7bSGuenter Roeck 		goto unlock;
101400b6a7bSGuenter Roeck 
102400b6a7bSGuenter Roeck 	switch (attr) {
103400b6a7bSGuenter Roeck 	case hwmon_temp_input:
104400b6a7bSGuenter Roeck 		if (!channel)
105400b6a7bSGuenter Roeck 			temp = get_unaligned_le16(log->temperature);
106400b6a7bSGuenter Roeck 		else
107400b6a7bSGuenter Roeck 			temp = le16_to_cpu(log->temp_sensor[channel - 1]);
108*52deba0fSAkinobu Mita 		*val = KELVIN_TO_MILLICELSIUS(temp);
109400b6a7bSGuenter Roeck 		break;
110400b6a7bSGuenter Roeck 	case hwmon_temp_alarm:
111400b6a7bSGuenter Roeck 		*val = !!(log->critical_warning & NVME_SMART_CRIT_TEMPERATURE);
112400b6a7bSGuenter Roeck 		break;
113400b6a7bSGuenter Roeck 	default:
114400b6a7bSGuenter Roeck 		err = -EOPNOTSUPP;
115400b6a7bSGuenter Roeck 		break;
116400b6a7bSGuenter Roeck 	}
117400b6a7bSGuenter Roeck unlock:
118400b6a7bSGuenter Roeck 	mutex_unlock(&data->read_lock);
119400b6a7bSGuenter Roeck 	return err;
120400b6a7bSGuenter Roeck }
121400b6a7bSGuenter Roeck 
122*52deba0fSAkinobu Mita static int nvme_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
123*52deba0fSAkinobu Mita 			    u32 attr, int channel, long val)
124*52deba0fSAkinobu Mita {
125*52deba0fSAkinobu Mita 	struct nvme_hwmon_data *data = dev_get_drvdata(dev);
126*52deba0fSAkinobu Mita 
127*52deba0fSAkinobu Mita 	switch (attr) {
128*52deba0fSAkinobu Mita 	case hwmon_temp_max:
129*52deba0fSAkinobu Mita 		return nvme_set_temp_thresh(data->ctrl, channel, false, val);
130*52deba0fSAkinobu Mita 	case hwmon_temp_min:
131*52deba0fSAkinobu Mita 		return nvme_set_temp_thresh(data->ctrl, channel, true, val);
132*52deba0fSAkinobu Mita 	default:
133*52deba0fSAkinobu Mita 		break;
134*52deba0fSAkinobu Mita 	}
135*52deba0fSAkinobu Mita 
136*52deba0fSAkinobu Mita 	return -EOPNOTSUPP;
137*52deba0fSAkinobu Mita }
138*52deba0fSAkinobu Mita 
139400b6a7bSGuenter Roeck static const char * const nvme_hwmon_sensor_names[] = {
140400b6a7bSGuenter Roeck 	"Composite",
141400b6a7bSGuenter Roeck 	"Sensor 1",
142400b6a7bSGuenter Roeck 	"Sensor 2",
143400b6a7bSGuenter Roeck 	"Sensor 3",
144400b6a7bSGuenter Roeck 	"Sensor 4",
145400b6a7bSGuenter Roeck 	"Sensor 5",
146400b6a7bSGuenter Roeck 	"Sensor 6",
147400b6a7bSGuenter Roeck 	"Sensor 7",
148400b6a7bSGuenter Roeck 	"Sensor 8",
149400b6a7bSGuenter Roeck };
150400b6a7bSGuenter Roeck 
151400b6a7bSGuenter Roeck static int nvme_hwmon_read_string(struct device *dev,
152400b6a7bSGuenter Roeck 				  enum hwmon_sensor_types type, u32 attr,
153400b6a7bSGuenter Roeck 				  int channel, const char **str)
154400b6a7bSGuenter Roeck {
155400b6a7bSGuenter Roeck 	*str = nvme_hwmon_sensor_names[channel];
156400b6a7bSGuenter Roeck 	return 0;
157400b6a7bSGuenter Roeck }
158400b6a7bSGuenter Roeck 
159400b6a7bSGuenter Roeck static umode_t nvme_hwmon_is_visible(const void *_data,
160400b6a7bSGuenter Roeck 				     enum hwmon_sensor_types type,
161400b6a7bSGuenter Roeck 				     u32 attr, int channel)
162400b6a7bSGuenter Roeck {
163400b6a7bSGuenter Roeck 	const struct nvme_hwmon_data *data = _data;
164400b6a7bSGuenter Roeck 
165400b6a7bSGuenter Roeck 	switch (attr) {
166400b6a7bSGuenter Roeck 	case hwmon_temp_crit:
167400b6a7bSGuenter Roeck 		if (!channel && data->ctrl->cctemp)
168400b6a7bSGuenter Roeck 			return 0444;
169400b6a7bSGuenter Roeck 		break;
170400b6a7bSGuenter Roeck 	case hwmon_temp_max:
171*52deba0fSAkinobu Mita 	case hwmon_temp_min:
172*52deba0fSAkinobu Mita 		if ((!channel && data->ctrl->wctemp) ||
173*52deba0fSAkinobu Mita 		    (channel && data->log.temp_sensor[channel - 1]))
174*52deba0fSAkinobu Mita 			return 0644;
175400b6a7bSGuenter Roeck 		break;
176400b6a7bSGuenter Roeck 	case hwmon_temp_alarm:
177400b6a7bSGuenter Roeck 		if (!channel)
178400b6a7bSGuenter Roeck 			return 0444;
179400b6a7bSGuenter Roeck 		break;
180400b6a7bSGuenter Roeck 	case hwmon_temp_input:
181400b6a7bSGuenter Roeck 	case hwmon_temp_label:
182400b6a7bSGuenter Roeck 		if (!channel || data->log.temp_sensor[channel - 1])
183400b6a7bSGuenter Roeck 			return 0444;
184400b6a7bSGuenter Roeck 		break;
185400b6a7bSGuenter Roeck 	default:
186400b6a7bSGuenter Roeck 		break;
187400b6a7bSGuenter Roeck 	}
188400b6a7bSGuenter Roeck 	return 0;
189400b6a7bSGuenter Roeck }
190400b6a7bSGuenter Roeck 
191400b6a7bSGuenter Roeck static const struct hwmon_channel_info *nvme_hwmon_info[] = {
192400b6a7bSGuenter Roeck 	HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
193400b6a7bSGuenter Roeck 	HWMON_CHANNEL_INFO(temp,
194*52deba0fSAkinobu Mita 			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN |
195*52deba0fSAkinobu Mita 				HWMON_T_CRIT | HWMON_T_LABEL | HWMON_T_ALARM,
196*52deba0fSAkinobu Mita 			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN |
197*52deba0fSAkinobu Mita 				HWMON_T_LABEL,
198*52deba0fSAkinobu Mita 			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN |
199*52deba0fSAkinobu Mita 				HWMON_T_LABEL,
200*52deba0fSAkinobu Mita 			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN |
201*52deba0fSAkinobu Mita 				HWMON_T_LABEL,
202*52deba0fSAkinobu Mita 			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN |
203*52deba0fSAkinobu Mita 				HWMON_T_LABEL,
204*52deba0fSAkinobu Mita 			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN |
205*52deba0fSAkinobu Mita 				HWMON_T_LABEL,
206*52deba0fSAkinobu Mita 			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN |
207*52deba0fSAkinobu Mita 				HWMON_T_LABEL,
208*52deba0fSAkinobu Mita 			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN |
209*52deba0fSAkinobu Mita 				HWMON_T_LABEL,
210*52deba0fSAkinobu Mita 			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN |
211*52deba0fSAkinobu Mita 				HWMON_T_LABEL),
212400b6a7bSGuenter Roeck 	NULL
213400b6a7bSGuenter Roeck };
214400b6a7bSGuenter Roeck 
215400b6a7bSGuenter Roeck static const struct hwmon_ops nvme_hwmon_ops = {
216400b6a7bSGuenter Roeck 	.is_visible	= nvme_hwmon_is_visible,
217400b6a7bSGuenter Roeck 	.read		= nvme_hwmon_read,
218400b6a7bSGuenter Roeck 	.read_string	= nvme_hwmon_read_string,
219*52deba0fSAkinobu Mita 	.write		= nvme_hwmon_write,
220400b6a7bSGuenter Roeck };
221400b6a7bSGuenter Roeck 
222400b6a7bSGuenter Roeck static const struct hwmon_chip_info nvme_hwmon_chip_info = {
223400b6a7bSGuenter Roeck 	.ops	= &nvme_hwmon_ops,
224400b6a7bSGuenter Roeck 	.info	= nvme_hwmon_info,
225400b6a7bSGuenter Roeck };
226400b6a7bSGuenter Roeck 
227400b6a7bSGuenter Roeck void nvme_hwmon_init(struct nvme_ctrl *ctrl)
228400b6a7bSGuenter Roeck {
229400b6a7bSGuenter Roeck 	struct device *dev = ctrl->dev;
230400b6a7bSGuenter Roeck 	struct nvme_hwmon_data *data;
231400b6a7bSGuenter Roeck 	struct device *hwmon;
232400b6a7bSGuenter Roeck 	int err;
233400b6a7bSGuenter Roeck 
234400b6a7bSGuenter Roeck 	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
235400b6a7bSGuenter Roeck 	if (!data)
236400b6a7bSGuenter Roeck 		return;
237400b6a7bSGuenter Roeck 
238400b6a7bSGuenter Roeck 	data->ctrl = ctrl;
239400b6a7bSGuenter Roeck 	mutex_init(&data->read_lock);
240400b6a7bSGuenter Roeck 
241400b6a7bSGuenter Roeck 	err = nvme_hwmon_get_smart_log(data);
242400b6a7bSGuenter Roeck 	if (err) {
243400b6a7bSGuenter Roeck 		dev_warn(dev, "Failed to read smart log (error %d)\n", err);
244400b6a7bSGuenter Roeck 		devm_kfree(dev, data);
245400b6a7bSGuenter Roeck 		return;
246400b6a7bSGuenter Roeck 	}
247400b6a7bSGuenter Roeck 
248400b6a7bSGuenter Roeck 	hwmon = devm_hwmon_device_register_with_info(dev, "nvme", data,
249400b6a7bSGuenter Roeck 						     &nvme_hwmon_chip_info,
250400b6a7bSGuenter Roeck 						     NULL);
251400b6a7bSGuenter Roeck 	if (IS_ERR(hwmon)) {
252400b6a7bSGuenter Roeck 		dev_warn(dev, "Failed to instantiate hwmon device\n");
253400b6a7bSGuenter Roeck 		devm_kfree(dev, data);
254400b6a7bSGuenter Roeck 	}
255400b6a7bSGuenter Roeck }
256