xref: /openbmc/linux/drivers/nvme/host/hwmon.c (revision 7724cd2bff55d29206d6f6d236ec222d155b2e41)
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>
8*7724cd2bSAkinobu 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;
15400b6a7bSGuenter Roeck 	struct nvme_smart_log log;
16400b6a7bSGuenter Roeck 	struct mutex read_lock;
17400b6a7bSGuenter Roeck };
18400b6a7bSGuenter Roeck 
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;
35*7724cd2bSAkinobu Mita 	*temp = kelvin_to_millicelsius(status & NVME_TEMP_THRESH_MASK);
3652deba0fSAkinobu Mita 
3752deba0fSAkinobu Mita 	return 0;
3852deba0fSAkinobu Mita }
3952deba0fSAkinobu Mita 
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 
46*7724cd2bSAkinobu 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 
60400b6a7bSGuenter Roeck static int nvme_hwmon_get_smart_log(struct nvme_hwmon_data *data)
61400b6a7bSGuenter Roeck {
62400b6a7bSGuenter Roeck 	int ret;
63400b6a7bSGuenter Roeck 
64400b6a7bSGuenter Roeck 	ret = nvme_get_log(data->ctrl, NVME_NSID_ALL, NVME_LOG_SMART, 0,
65400b6a7bSGuenter Roeck 			   &data->log, sizeof(data->log), 0);
66400b6a7bSGuenter Roeck 
67400b6a7bSGuenter Roeck 	return ret <= 0 ? ret : -EIO;
68400b6a7bSGuenter Roeck }
69400b6a7bSGuenter Roeck 
70400b6a7bSGuenter Roeck static int nvme_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
71400b6a7bSGuenter Roeck 			   u32 attr, int channel, long *val)
72400b6a7bSGuenter Roeck {
73400b6a7bSGuenter Roeck 	struct nvme_hwmon_data *data = dev_get_drvdata(dev);
74400b6a7bSGuenter Roeck 	struct nvme_smart_log *log = &data->log;
75400b6a7bSGuenter Roeck 	int temp;
76400b6a7bSGuenter Roeck 	int err;
77400b6a7bSGuenter Roeck 
78400b6a7bSGuenter Roeck 	/*
79400b6a7bSGuenter Roeck 	 * First handle attributes which don't require us to read
80400b6a7bSGuenter Roeck 	 * the smart log.
81400b6a7bSGuenter Roeck 	 */
82400b6a7bSGuenter Roeck 	switch (attr) {
83400b6a7bSGuenter Roeck 	case hwmon_temp_max:
8452deba0fSAkinobu Mita 		return nvme_get_temp_thresh(data->ctrl, channel, false, val);
8552deba0fSAkinobu Mita 	case hwmon_temp_min:
8652deba0fSAkinobu Mita 		return nvme_get_temp_thresh(data->ctrl, channel, true, val);
87400b6a7bSGuenter Roeck 	case hwmon_temp_crit:
88*7724cd2bSAkinobu Mita 		*val = kelvin_to_millicelsius(data->ctrl->cctemp);
89400b6a7bSGuenter Roeck 		return 0;
90400b6a7bSGuenter Roeck 	default:
91400b6a7bSGuenter Roeck 		break;
92400b6a7bSGuenter Roeck 	}
93400b6a7bSGuenter Roeck 
94400b6a7bSGuenter Roeck 	mutex_lock(&data->read_lock);
95400b6a7bSGuenter Roeck 	err = nvme_hwmon_get_smart_log(data);
96400b6a7bSGuenter Roeck 	if (err)
97400b6a7bSGuenter Roeck 		goto unlock;
98400b6a7bSGuenter Roeck 
99400b6a7bSGuenter Roeck 	switch (attr) {
100400b6a7bSGuenter Roeck 	case hwmon_temp_input:
101400b6a7bSGuenter Roeck 		if (!channel)
102400b6a7bSGuenter Roeck 			temp = get_unaligned_le16(log->temperature);
103400b6a7bSGuenter Roeck 		else
104400b6a7bSGuenter Roeck 			temp = le16_to_cpu(log->temp_sensor[channel - 1]);
105*7724cd2bSAkinobu Mita 		*val = kelvin_to_millicelsius(temp);
106400b6a7bSGuenter Roeck 		break;
107400b6a7bSGuenter Roeck 	case hwmon_temp_alarm:
108400b6a7bSGuenter Roeck 		*val = !!(log->critical_warning & NVME_SMART_CRIT_TEMPERATURE);
109400b6a7bSGuenter Roeck 		break;
110400b6a7bSGuenter Roeck 	default:
111400b6a7bSGuenter Roeck 		err = -EOPNOTSUPP;
112400b6a7bSGuenter Roeck 		break;
113400b6a7bSGuenter Roeck 	}
114400b6a7bSGuenter Roeck unlock:
115400b6a7bSGuenter Roeck 	mutex_unlock(&data->read_lock);
116400b6a7bSGuenter Roeck 	return err;
117400b6a7bSGuenter Roeck }
118400b6a7bSGuenter Roeck 
11952deba0fSAkinobu Mita static int nvme_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
12052deba0fSAkinobu Mita 			    u32 attr, int channel, long val)
12152deba0fSAkinobu Mita {
12252deba0fSAkinobu Mita 	struct nvme_hwmon_data *data = dev_get_drvdata(dev);
12352deba0fSAkinobu Mita 
12452deba0fSAkinobu Mita 	switch (attr) {
12552deba0fSAkinobu Mita 	case hwmon_temp_max:
12652deba0fSAkinobu Mita 		return nvme_set_temp_thresh(data->ctrl, channel, false, val);
12752deba0fSAkinobu Mita 	case hwmon_temp_min:
12852deba0fSAkinobu Mita 		return nvme_set_temp_thresh(data->ctrl, channel, true, val);
12952deba0fSAkinobu Mita 	default:
13052deba0fSAkinobu Mita 		break;
13152deba0fSAkinobu Mita 	}
13252deba0fSAkinobu Mita 
13352deba0fSAkinobu Mita 	return -EOPNOTSUPP;
13452deba0fSAkinobu Mita }
13552deba0fSAkinobu Mita 
136400b6a7bSGuenter Roeck static const char * const nvme_hwmon_sensor_names[] = {
137400b6a7bSGuenter Roeck 	"Composite",
138400b6a7bSGuenter Roeck 	"Sensor 1",
139400b6a7bSGuenter Roeck 	"Sensor 2",
140400b6a7bSGuenter Roeck 	"Sensor 3",
141400b6a7bSGuenter Roeck 	"Sensor 4",
142400b6a7bSGuenter Roeck 	"Sensor 5",
143400b6a7bSGuenter Roeck 	"Sensor 6",
144400b6a7bSGuenter Roeck 	"Sensor 7",
145400b6a7bSGuenter Roeck 	"Sensor 8",
146400b6a7bSGuenter Roeck };
147400b6a7bSGuenter Roeck 
148400b6a7bSGuenter Roeck static int nvme_hwmon_read_string(struct device *dev,
149400b6a7bSGuenter Roeck 				  enum hwmon_sensor_types type, u32 attr,
150400b6a7bSGuenter Roeck 				  int channel, const char **str)
151400b6a7bSGuenter Roeck {
152400b6a7bSGuenter Roeck 	*str = nvme_hwmon_sensor_names[channel];
153400b6a7bSGuenter Roeck 	return 0;
154400b6a7bSGuenter Roeck }
155400b6a7bSGuenter Roeck 
156400b6a7bSGuenter Roeck static umode_t nvme_hwmon_is_visible(const void *_data,
157400b6a7bSGuenter Roeck 				     enum hwmon_sensor_types type,
158400b6a7bSGuenter Roeck 				     u32 attr, int channel)
159400b6a7bSGuenter Roeck {
160400b6a7bSGuenter Roeck 	const struct nvme_hwmon_data *data = _data;
161400b6a7bSGuenter Roeck 
162400b6a7bSGuenter Roeck 	switch (attr) {
163400b6a7bSGuenter Roeck 	case hwmon_temp_crit:
164400b6a7bSGuenter Roeck 		if (!channel && data->ctrl->cctemp)
165400b6a7bSGuenter Roeck 			return 0444;
166400b6a7bSGuenter Roeck 		break;
167400b6a7bSGuenter Roeck 	case hwmon_temp_max:
16852deba0fSAkinobu Mita 	case hwmon_temp_min:
16952deba0fSAkinobu Mita 		if ((!channel && data->ctrl->wctemp) ||
1706c6aa2f2SAkinobu Mita 		    (channel && data->log.temp_sensor[channel - 1])) {
1716c6aa2f2SAkinobu Mita 			if (data->ctrl->quirks &
1726c6aa2f2SAkinobu Mita 			    NVME_QUIRK_NO_TEMP_THRESH_CHANGE)
1736c6aa2f2SAkinobu Mita 				return 0444;
17452deba0fSAkinobu Mita 			return 0644;
1756c6aa2f2SAkinobu Mita 		}
176400b6a7bSGuenter Roeck 		break;
177400b6a7bSGuenter Roeck 	case hwmon_temp_alarm:
178400b6a7bSGuenter Roeck 		if (!channel)
179400b6a7bSGuenter Roeck 			return 0444;
180400b6a7bSGuenter Roeck 		break;
181400b6a7bSGuenter Roeck 	case hwmon_temp_input:
182400b6a7bSGuenter Roeck 	case hwmon_temp_label:
183400b6a7bSGuenter Roeck 		if (!channel || data->log.temp_sensor[channel - 1])
184400b6a7bSGuenter Roeck 			return 0444;
185400b6a7bSGuenter Roeck 		break;
186400b6a7bSGuenter Roeck 	default:
187400b6a7bSGuenter Roeck 		break;
188400b6a7bSGuenter Roeck 	}
189400b6a7bSGuenter Roeck 	return 0;
190400b6a7bSGuenter Roeck }
191400b6a7bSGuenter Roeck 
192400b6a7bSGuenter Roeck static const struct hwmon_channel_info *nvme_hwmon_info[] = {
193400b6a7bSGuenter Roeck 	HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
194400b6a7bSGuenter Roeck 	HWMON_CHANNEL_INFO(temp,
19552deba0fSAkinobu Mita 			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN |
19652deba0fSAkinobu Mita 				HWMON_T_CRIT | HWMON_T_LABEL | HWMON_T_ALARM,
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,
21152deba0fSAkinobu Mita 			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN |
21252deba0fSAkinobu Mita 				HWMON_T_LABEL),
213400b6a7bSGuenter Roeck 	NULL
214400b6a7bSGuenter Roeck };
215400b6a7bSGuenter Roeck 
216400b6a7bSGuenter Roeck static const struct hwmon_ops nvme_hwmon_ops = {
217400b6a7bSGuenter Roeck 	.is_visible	= nvme_hwmon_is_visible,
218400b6a7bSGuenter Roeck 	.read		= nvme_hwmon_read,
219400b6a7bSGuenter Roeck 	.read_string	= nvme_hwmon_read_string,
22052deba0fSAkinobu Mita 	.write		= nvme_hwmon_write,
221400b6a7bSGuenter Roeck };
222400b6a7bSGuenter Roeck 
223400b6a7bSGuenter Roeck static const struct hwmon_chip_info nvme_hwmon_chip_info = {
224400b6a7bSGuenter Roeck 	.ops	= &nvme_hwmon_ops,
225400b6a7bSGuenter Roeck 	.info	= nvme_hwmon_info,
226400b6a7bSGuenter Roeck };
227400b6a7bSGuenter Roeck 
228400b6a7bSGuenter Roeck void nvme_hwmon_init(struct nvme_ctrl *ctrl)
229400b6a7bSGuenter Roeck {
230400b6a7bSGuenter Roeck 	struct device *dev = ctrl->dev;
231400b6a7bSGuenter Roeck 	struct nvme_hwmon_data *data;
232400b6a7bSGuenter Roeck 	struct device *hwmon;
233400b6a7bSGuenter Roeck 	int err;
234400b6a7bSGuenter Roeck 
235400b6a7bSGuenter Roeck 	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
236400b6a7bSGuenter Roeck 	if (!data)
237400b6a7bSGuenter Roeck 		return;
238400b6a7bSGuenter Roeck 
239400b6a7bSGuenter Roeck 	data->ctrl = ctrl;
240400b6a7bSGuenter Roeck 	mutex_init(&data->read_lock);
241400b6a7bSGuenter Roeck 
242400b6a7bSGuenter Roeck 	err = nvme_hwmon_get_smart_log(data);
243400b6a7bSGuenter Roeck 	if (err) {
244400b6a7bSGuenter Roeck 		dev_warn(dev, "Failed to read smart log (error %d)\n", err);
245400b6a7bSGuenter Roeck 		devm_kfree(dev, data);
246400b6a7bSGuenter Roeck 		return;
247400b6a7bSGuenter Roeck 	}
248400b6a7bSGuenter Roeck 
249400b6a7bSGuenter Roeck 	hwmon = devm_hwmon_device_register_with_info(dev, "nvme", data,
250400b6a7bSGuenter Roeck 						     &nvme_hwmon_chip_info,
251400b6a7bSGuenter Roeck 						     NULL);
252400b6a7bSGuenter Roeck 	if (IS_ERR(hwmon)) {
253400b6a7bSGuenter Roeck 		dev_warn(dev, "Failed to instantiate hwmon device\n");
254400b6a7bSGuenter Roeck 		devm_kfree(dev, data);
255400b6a7bSGuenter Roeck 	}
256400b6a7bSGuenter Roeck }
257