xref: /openbmc/linux/drivers/nvme/host/hwmon.c (revision 5804c19b80bf625c6a9925317f845e497434d6d3)
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>
87724cd2bSAkinobu Mita #include <linux/units.h>
9400b6a7bSGuenter Roeck #include <asm/unaligned.h>
10400b6a7bSGuenter Roeck 
11400b6a7bSGuenter Roeck #include "nvme.h"
12400b6a7bSGuenter Roeck 
13400b6a7bSGuenter Roeck struct nvme_hwmon_data {
14400b6a7bSGuenter Roeck 	struct nvme_ctrl *ctrl;
15c94b7f9bSSerge Semin 	struct nvme_smart_log *log;
16400b6a7bSGuenter Roeck 	struct mutex read_lock;
17400b6a7bSGuenter Roeck };
18400b6a7bSGuenter Roeck 
nvme_get_temp_thresh(struct nvme_ctrl * ctrl,int sensor,bool under,long * temp)1952deba0fSAkinobu Mita static int nvme_get_temp_thresh(struct nvme_ctrl *ctrl, int sensor, bool under,
2052deba0fSAkinobu Mita 				long *temp)
2152deba0fSAkinobu Mita {
2252deba0fSAkinobu Mita 	unsigned int threshold = sensor << NVME_TEMP_THRESH_SELECT_SHIFT;
2352deba0fSAkinobu Mita 	u32 status;
2452deba0fSAkinobu Mita 	int ret;
2552deba0fSAkinobu Mita 
2652deba0fSAkinobu Mita 	if (under)
2752deba0fSAkinobu Mita 		threshold |= NVME_TEMP_THRESH_TYPE_UNDER;
2852deba0fSAkinobu Mita 
2952deba0fSAkinobu Mita 	ret = nvme_get_features(ctrl, NVME_FEAT_TEMP_THRESH, threshold, NULL, 0,
3052deba0fSAkinobu Mita 				&status);
3152deba0fSAkinobu Mita 	if (ret > 0)
3252deba0fSAkinobu Mita 		return -EIO;
3352deba0fSAkinobu Mita 	if (ret < 0)
3452deba0fSAkinobu Mita 		return ret;
357724cd2bSAkinobu Mita 	*temp = kelvin_to_millicelsius(status & NVME_TEMP_THRESH_MASK);
3652deba0fSAkinobu Mita 
3752deba0fSAkinobu Mita 	return 0;
3852deba0fSAkinobu Mita }
3952deba0fSAkinobu Mita 
nvme_set_temp_thresh(struct nvme_ctrl * ctrl,int sensor,bool under,long temp)4052deba0fSAkinobu Mita static int nvme_set_temp_thresh(struct nvme_ctrl *ctrl, int sensor, bool under,
4152deba0fSAkinobu Mita 				long temp)
4252deba0fSAkinobu Mita {
4352deba0fSAkinobu Mita 	unsigned int threshold = sensor << NVME_TEMP_THRESH_SELECT_SHIFT;
4452deba0fSAkinobu Mita 	int ret;
4552deba0fSAkinobu Mita 
467724cd2bSAkinobu Mita 	temp = millicelsius_to_kelvin(temp);
4752deba0fSAkinobu Mita 	threshold |= clamp_val(temp, 0, NVME_TEMP_THRESH_MASK);
4852deba0fSAkinobu Mita 
4952deba0fSAkinobu Mita 	if (under)
5052deba0fSAkinobu Mita 		threshold |= NVME_TEMP_THRESH_TYPE_UNDER;
5152deba0fSAkinobu Mita 
5252deba0fSAkinobu Mita 	ret = nvme_set_features(ctrl, NVME_FEAT_TEMP_THRESH, threshold, NULL, 0,
5352deba0fSAkinobu Mita 				NULL);
5452deba0fSAkinobu Mita 	if (ret > 0)
5552deba0fSAkinobu Mita 		return -EIO;
5652deba0fSAkinobu Mita 
5752deba0fSAkinobu Mita 	return ret;
5852deba0fSAkinobu Mita }
5952deba0fSAkinobu Mita 
nvme_hwmon_get_smart_log(struct nvme_hwmon_data * data)60400b6a7bSGuenter Roeck static int nvme_hwmon_get_smart_log(struct nvme_hwmon_data *data)
61400b6a7bSGuenter Roeck {
6259e330f8SKeith Busch 	return nvme_get_log(data->ctrl, NVME_NSID_ALL, NVME_LOG_SMART, 0,
63c94b7f9bSSerge Semin 			   NVME_CSI_NVM, data->log, sizeof(*data->log), 0);
64400b6a7bSGuenter Roeck }
65400b6a7bSGuenter Roeck 
nvme_hwmon_read(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long * val)66400b6a7bSGuenter Roeck static int nvme_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
67400b6a7bSGuenter Roeck 			   u32 attr, int channel, long *val)
68400b6a7bSGuenter Roeck {
69400b6a7bSGuenter Roeck 	struct nvme_hwmon_data *data = dev_get_drvdata(dev);
70c94b7f9bSSerge Semin 	struct nvme_smart_log *log = data->log;
71400b6a7bSGuenter Roeck 	int temp;
72400b6a7bSGuenter Roeck 	int err;
73400b6a7bSGuenter Roeck 
74400b6a7bSGuenter Roeck 	/*
75400b6a7bSGuenter Roeck 	 * First handle attributes which don't require us to read
76400b6a7bSGuenter Roeck 	 * the smart log.
77400b6a7bSGuenter Roeck 	 */
78400b6a7bSGuenter Roeck 	switch (attr) {
79400b6a7bSGuenter Roeck 	case hwmon_temp_max:
8052deba0fSAkinobu Mita 		return nvme_get_temp_thresh(data->ctrl, channel, false, val);
8152deba0fSAkinobu Mita 	case hwmon_temp_min:
8252deba0fSAkinobu Mita 		return nvme_get_temp_thresh(data->ctrl, channel, true, val);
83400b6a7bSGuenter Roeck 	case hwmon_temp_crit:
847724cd2bSAkinobu Mita 		*val = kelvin_to_millicelsius(data->ctrl->cctemp);
85400b6a7bSGuenter Roeck 		return 0;
86400b6a7bSGuenter Roeck 	default:
87400b6a7bSGuenter Roeck 		break;
88400b6a7bSGuenter Roeck 	}
89400b6a7bSGuenter Roeck 
90400b6a7bSGuenter Roeck 	mutex_lock(&data->read_lock);
91400b6a7bSGuenter Roeck 	err = nvme_hwmon_get_smart_log(data);
92400b6a7bSGuenter Roeck 	if (err)
93400b6a7bSGuenter Roeck 		goto unlock;
94400b6a7bSGuenter Roeck 
95400b6a7bSGuenter Roeck 	switch (attr) {
96400b6a7bSGuenter Roeck 	case hwmon_temp_input:
97400b6a7bSGuenter Roeck 		if (!channel)
98400b6a7bSGuenter Roeck 			temp = get_unaligned_le16(log->temperature);
99400b6a7bSGuenter Roeck 		else
100400b6a7bSGuenter Roeck 			temp = le16_to_cpu(log->temp_sensor[channel - 1]);
1017724cd2bSAkinobu Mita 		*val = kelvin_to_millicelsius(temp);
102400b6a7bSGuenter Roeck 		break;
103400b6a7bSGuenter Roeck 	case hwmon_temp_alarm:
104400b6a7bSGuenter Roeck 		*val = !!(log->critical_warning & NVME_SMART_CRIT_TEMPERATURE);
105400b6a7bSGuenter Roeck 		break;
106400b6a7bSGuenter Roeck 	default:
107400b6a7bSGuenter Roeck 		err = -EOPNOTSUPP;
108400b6a7bSGuenter Roeck 		break;
109400b6a7bSGuenter Roeck 	}
110400b6a7bSGuenter Roeck unlock:
111400b6a7bSGuenter Roeck 	mutex_unlock(&data->read_lock);
112400b6a7bSGuenter Roeck 	return err;
113400b6a7bSGuenter Roeck }
114400b6a7bSGuenter Roeck 
nvme_hwmon_write(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long val)11552deba0fSAkinobu Mita static int nvme_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
11652deba0fSAkinobu Mita 			    u32 attr, int channel, long val)
11752deba0fSAkinobu Mita {
11852deba0fSAkinobu Mita 	struct nvme_hwmon_data *data = dev_get_drvdata(dev);
11952deba0fSAkinobu Mita 
12052deba0fSAkinobu Mita 	switch (attr) {
12152deba0fSAkinobu Mita 	case hwmon_temp_max:
12252deba0fSAkinobu Mita 		return nvme_set_temp_thresh(data->ctrl, channel, false, val);
12352deba0fSAkinobu Mita 	case hwmon_temp_min:
12452deba0fSAkinobu Mita 		return nvme_set_temp_thresh(data->ctrl, channel, true, val);
12552deba0fSAkinobu Mita 	default:
12652deba0fSAkinobu Mita 		break;
12752deba0fSAkinobu Mita 	}
12852deba0fSAkinobu Mita 
12952deba0fSAkinobu Mita 	return -EOPNOTSUPP;
13052deba0fSAkinobu Mita }
13152deba0fSAkinobu Mita 
132400b6a7bSGuenter Roeck static const char * const nvme_hwmon_sensor_names[] = {
133400b6a7bSGuenter Roeck 	"Composite",
134400b6a7bSGuenter Roeck 	"Sensor 1",
135400b6a7bSGuenter Roeck 	"Sensor 2",
136400b6a7bSGuenter Roeck 	"Sensor 3",
137400b6a7bSGuenter Roeck 	"Sensor 4",
138400b6a7bSGuenter Roeck 	"Sensor 5",
139400b6a7bSGuenter Roeck 	"Sensor 6",
140400b6a7bSGuenter Roeck 	"Sensor 7",
141400b6a7bSGuenter Roeck 	"Sensor 8",
142400b6a7bSGuenter Roeck };
143400b6a7bSGuenter Roeck 
nvme_hwmon_read_string(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,const char ** str)144400b6a7bSGuenter Roeck static int nvme_hwmon_read_string(struct device *dev,
145400b6a7bSGuenter Roeck 				  enum hwmon_sensor_types type, u32 attr,
146400b6a7bSGuenter Roeck 				  int channel, const char **str)
147400b6a7bSGuenter Roeck {
148400b6a7bSGuenter Roeck 	*str = nvme_hwmon_sensor_names[channel];
149400b6a7bSGuenter Roeck 	return 0;
150400b6a7bSGuenter Roeck }
151400b6a7bSGuenter Roeck 
nvme_hwmon_is_visible(const void * _data,enum hwmon_sensor_types type,u32 attr,int channel)152400b6a7bSGuenter Roeck static umode_t nvme_hwmon_is_visible(const void *_data,
153400b6a7bSGuenter Roeck 				     enum hwmon_sensor_types type,
154400b6a7bSGuenter Roeck 				     u32 attr, int channel)
155400b6a7bSGuenter Roeck {
156400b6a7bSGuenter Roeck 	const struct nvme_hwmon_data *data = _data;
157400b6a7bSGuenter Roeck 
158400b6a7bSGuenter Roeck 	switch (attr) {
159400b6a7bSGuenter Roeck 	case hwmon_temp_crit:
160400b6a7bSGuenter Roeck 		if (!channel && data->ctrl->cctemp)
161400b6a7bSGuenter Roeck 			return 0444;
162400b6a7bSGuenter Roeck 		break;
163400b6a7bSGuenter Roeck 	case hwmon_temp_max:
16452deba0fSAkinobu Mita 	case hwmon_temp_min:
16552deba0fSAkinobu Mita 		if ((!channel && data->ctrl->wctemp) ||
166bd375feeSHristo Venev 		    (channel && data->log->temp_sensor[channel - 1] &&
167bd375feeSHristo Venev 		     !(data->ctrl->quirks &
168bd375feeSHristo Venev 		       NVME_QUIRK_NO_SECONDARY_TEMP_THRESH))) {
1696c6aa2f2SAkinobu Mita 			if (data->ctrl->quirks &
1706c6aa2f2SAkinobu Mita 			    NVME_QUIRK_NO_TEMP_THRESH_CHANGE)
1716c6aa2f2SAkinobu Mita 				return 0444;
17252deba0fSAkinobu Mita 			return 0644;
1736c6aa2f2SAkinobu Mita 		}
174400b6a7bSGuenter Roeck 		break;
175400b6a7bSGuenter Roeck 	case hwmon_temp_alarm:
176400b6a7bSGuenter Roeck 		if (!channel)
177400b6a7bSGuenter Roeck 			return 0444;
178400b6a7bSGuenter Roeck 		break;
179400b6a7bSGuenter Roeck 	case hwmon_temp_input:
180400b6a7bSGuenter Roeck 	case hwmon_temp_label:
181c94b7f9bSSerge Semin 		if (!channel || data->log->temp_sensor[channel - 1])
182400b6a7bSGuenter Roeck 			return 0444;
183400b6a7bSGuenter Roeck 		break;
184400b6a7bSGuenter Roeck 	default:
185400b6a7bSGuenter Roeck 		break;
186400b6a7bSGuenter Roeck 	}
187400b6a7bSGuenter Roeck 	return 0;
188400b6a7bSGuenter Roeck }
189400b6a7bSGuenter Roeck 
190*71be8684SKrzysztof Kozlowski static const struct hwmon_channel_info *const nvme_hwmon_info[] = {
191400b6a7bSGuenter Roeck 	HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
192400b6a7bSGuenter Roeck 	HWMON_CHANNEL_INFO(temp,
19352deba0fSAkinobu Mita 			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN |
19452deba0fSAkinobu Mita 				HWMON_T_CRIT | HWMON_T_LABEL | HWMON_T_ALARM,
19552deba0fSAkinobu Mita 			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN |
19652deba0fSAkinobu Mita 				HWMON_T_LABEL,
19752deba0fSAkinobu Mita 			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN |
19852deba0fSAkinobu Mita 				HWMON_T_LABEL,
19952deba0fSAkinobu Mita 			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN |
20052deba0fSAkinobu Mita 				HWMON_T_LABEL,
20152deba0fSAkinobu Mita 			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN |
20252deba0fSAkinobu Mita 				HWMON_T_LABEL,
20352deba0fSAkinobu Mita 			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN |
20452deba0fSAkinobu Mita 				HWMON_T_LABEL,
20552deba0fSAkinobu Mita 			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN |
20652deba0fSAkinobu Mita 				HWMON_T_LABEL,
20752deba0fSAkinobu Mita 			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN |
20852deba0fSAkinobu Mita 				HWMON_T_LABEL,
20952deba0fSAkinobu Mita 			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN |
21052deba0fSAkinobu Mita 				HWMON_T_LABEL),
211400b6a7bSGuenter Roeck 	NULL
212400b6a7bSGuenter Roeck };
213400b6a7bSGuenter Roeck 
214400b6a7bSGuenter Roeck static const struct hwmon_ops nvme_hwmon_ops = {
215400b6a7bSGuenter Roeck 	.is_visible	= nvme_hwmon_is_visible,
216400b6a7bSGuenter Roeck 	.read		= nvme_hwmon_read,
217400b6a7bSGuenter Roeck 	.read_string	= nvme_hwmon_read_string,
21852deba0fSAkinobu Mita 	.write		= nvme_hwmon_write,
219400b6a7bSGuenter Roeck };
220400b6a7bSGuenter Roeck 
221400b6a7bSGuenter Roeck static const struct hwmon_chip_info nvme_hwmon_chip_info = {
222400b6a7bSGuenter Roeck 	.ops	= &nvme_hwmon_ops,
223400b6a7bSGuenter Roeck 	.info	= nvme_hwmon_info,
224400b6a7bSGuenter Roeck };
225400b6a7bSGuenter Roeck 
nvme_hwmon_init(struct nvme_ctrl * ctrl)22659e330f8SKeith Busch int nvme_hwmon_init(struct nvme_ctrl *ctrl)
227400b6a7bSGuenter Roeck {
228ed7770f6SHannes Reinecke 	struct device *dev = ctrl->device;
229400b6a7bSGuenter Roeck 	struct nvme_hwmon_data *data;
230400b6a7bSGuenter Roeck 	struct device *hwmon;
231400b6a7bSGuenter Roeck 	int err;
232400b6a7bSGuenter Roeck 
233ed7770f6SHannes Reinecke 	data = kzalloc(sizeof(*data), GFP_KERNEL);
234400b6a7bSGuenter Roeck 	if (!data)
2356b8cf940SChristoph Hellwig 		return -ENOMEM;
236400b6a7bSGuenter Roeck 
237c94b7f9bSSerge Semin 	data->log = kzalloc(sizeof(*data->log), GFP_KERNEL);
238c94b7f9bSSerge Semin 	if (!data->log) {
239c94b7f9bSSerge Semin 		err = -ENOMEM;
240c94b7f9bSSerge Semin 		goto err_free_data;
241c94b7f9bSSerge Semin 	}
242c94b7f9bSSerge Semin 
243400b6a7bSGuenter Roeck 	data->ctrl = ctrl;
244400b6a7bSGuenter Roeck 	mutex_init(&data->read_lock);
245400b6a7bSGuenter Roeck 
246400b6a7bSGuenter Roeck 	err = nvme_hwmon_get_smart_log(data);
247400b6a7bSGuenter Roeck 	if (err) {
248ed7770f6SHannes Reinecke 		dev_warn(dev, "Failed to read smart log (error %d)\n", err);
249c94b7f9bSSerge Semin 		goto err_free_log;
250400b6a7bSGuenter Roeck 	}
251400b6a7bSGuenter Roeck 
252ed7770f6SHannes Reinecke 	hwmon = hwmon_device_register_with_info(dev, "nvme",
253ed7770f6SHannes Reinecke 						data, &nvme_hwmon_chip_info,
254400b6a7bSGuenter Roeck 						NULL);
255400b6a7bSGuenter Roeck 	if (IS_ERR(hwmon)) {
256400b6a7bSGuenter Roeck 		dev_warn(dev, "Failed to instantiate hwmon device\n");
2576b8cf940SChristoph Hellwig 		err = PTR_ERR(hwmon);
258c94b7f9bSSerge Semin 		goto err_free_log;
259ed7770f6SHannes Reinecke 	}
260ed7770f6SHannes Reinecke 	ctrl->hwmon_device = hwmon;
261ed7770f6SHannes Reinecke 	return 0;
2626b8cf940SChristoph Hellwig 
263c94b7f9bSSerge Semin err_free_log:
264c94b7f9bSSerge Semin 	kfree(data->log);
2656b8cf940SChristoph Hellwig err_free_data:
2666b8cf940SChristoph Hellwig 	kfree(data);
2676b8cf940SChristoph Hellwig 	return err;
268400b6a7bSGuenter Roeck }
26959e330f8SKeith Busch 
nvme_hwmon_exit(struct nvme_ctrl * ctrl)270ed7770f6SHannes Reinecke void nvme_hwmon_exit(struct nvme_ctrl *ctrl)
271ed7770f6SHannes Reinecke {
272ed7770f6SHannes Reinecke 	if (ctrl->hwmon_device) {
273ed7770f6SHannes Reinecke 		struct nvme_hwmon_data *data =
274ed7770f6SHannes Reinecke 			dev_get_drvdata(ctrl->hwmon_device);
275ed7770f6SHannes Reinecke 
276ed7770f6SHannes Reinecke 		hwmon_device_unregister(ctrl->hwmon_device);
277ed7770f6SHannes Reinecke 		ctrl->hwmon_device = NULL;
278c94b7f9bSSerge Semin 		kfree(data->log);
279ed7770f6SHannes Reinecke 		kfree(data);
280ed7770f6SHannes Reinecke 	}
281400b6a7bSGuenter Roeck }
282