1 // SPDX-License-Identifier: GPL-2.0
3 * NVM Express hardware monitoring support
4 * Copyright (c) 2019, Guenter Roeck
7 #include <linux/hwmon.h>
8 #include <linux/units.h>
9 #include <asm/unaligned.h>
13 struct nvme_hwmon_data
{
14 struct nvme_ctrl
*ctrl
;
15 struct nvme_smart_log log
;
16 struct mutex read_lock
;
19 static int nvme_get_temp_thresh(struct nvme_ctrl
*ctrl
, int sensor
, bool under
,
22 unsigned int threshold
= sensor
<< NVME_TEMP_THRESH_SELECT_SHIFT
;
27 threshold
|= NVME_TEMP_THRESH_TYPE_UNDER
;
29 ret
= nvme_get_features(ctrl
, NVME_FEAT_TEMP_THRESH
, threshold
, NULL
, 0,
35 *temp
= kelvin_to_millicelsius(status
& NVME_TEMP_THRESH_MASK
);
40 static int nvme_set_temp_thresh(struct nvme_ctrl
*ctrl
, int sensor
, bool under
,
43 unsigned int threshold
= sensor
<< NVME_TEMP_THRESH_SELECT_SHIFT
;
46 temp
= millicelsius_to_kelvin(temp
);
47 threshold
|= clamp_val(temp
, 0, NVME_TEMP_THRESH_MASK
);
50 threshold
|= NVME_TEMP_THRESH_TYPE_UNDER
;
52 ret
= nvme_set_features(ctrl
, NVME_FEAT_TEMP_THRESH
, threshold
, NULL
, 0,
60 static int nvme_hwmon_get_smart_log(struct nvme_hwmon_data
*data
)
62 return nvme_get_log(data
->ctrl
, NVME_NSID_ALL
, NVME_LOG_SMART
, 0,
63 NVME_CSI_NVM
, &data
->log
, sizeof(data
->log
), 0);
66 static int nvme_hwmon_read(struct device
*dev
, enum hwmon_sensor_types type
,
67 u32 attr
, int channel
, long *val
)
69 struct nvme_hwmon_data
*data
= dev_get_drvdata(dev
);
70 struct nvme_smart_log
*log
= &data
->log
;
75 * First handle attributes which don't require us to read
80 return nvme_get_temp_thresh(data
->ctrl
, channel
, false, val
);
82 return nvme_get_temp_thresh(data
->ctrl
, channel
, true, val
);
84 *val
= kelvin_to_millicelsius(data
->ctrl
->cctemp
);
90 mutex_lock(&data
->read_lock
);
91 err
= nvme_hwmon_get_smart_log(data
);
96 case hwmon_temp_input
:
98 temp
= get_unaligned_le16(log
->temperature
);
100 temp
= le16_to_cpu(log
->temp_sensor
[channel
- 1]);
101 *val
= kelvin_to_millicelsius(temp
);
103 case hwmon_temp_alarm
:
104 *val
= !!(log
->critical_warning
& NVME_SMART_CRIT_TEMPERATURE
);
111 mutex_unlock(&data
->read_lock
);
115 static int nvme_hwmon_write(struct device
*dev
, enum hwmon_sensor_types type
,
116 u32 attr
, int channel
, long val
)
118 struct nvme_hwmon_data
*data
= dev_get_drvdata(dev
);
122 return nvme_set_temp_thresh(data
->ctrl
, channel
, false, val
);
124 return nvme_set_temp_thresh(data
->ctrl
, channel
, true, val
);
132 static const char * const nvme_hwmon_sensor_names
[] = {
144 static int nvme_hwmon_read_string(struct device
*dev
,
145 enum hwmon_sensor_types type
, u32 attr
,
146 int channel
, const char **str
)
148 *str
= nvme_hwmon_sensor_names
[channel
];
152 static umode_t
nvme_hwmon_is_visible(const void *_data
,
153 enum hwmon_sensor_types type
,
154 u32 attr
, int channel
)
156 const struct nvme_hwmon_data
*data
= _data
;
159 case hwmon_temp_crit
:
160 if (!channel
&& data
->ctrl
->cctemp
)
165 if ((!channel
&& data
->ctrl
->wctemp
) ||
166 (channel
&& data
->log
.temp_sensor
[channel
- 1])) {
167 if (data
->ctrl
->quirks
&
168 NVME_QUIRK_NO_TEMP_THRESH_CHANGE
)
173 case hwmon_temp_alarm
:
177 case hwmon_temp_input
:
178 case hwmon_temp_label
:
179 if (!channel
|| data
->log
.temp_sensor
[channel
- 1])
188 static const struct hwmon_channel_info
*nvme_hwmon_info
[] = {
189 HWMON_CHANNEL_INFO(chip
, HWMON_C_REGISTER_TZ
),
190 HWMON_CHANNEL_INFO(temp
,
191 HWMON_T_INPUT
| HWMON_T_MAX
| HWMON_T_MIN
|
192 HWMON_T_CRIT
| HWMON_T_LABEL
| HWMON_T_ALARM
,
193 HWMON_T_INPUT
| HWMON_T_MAX
| HWMON_T_MIN
|
195 HWMON_T_INPUT
| HWMON_T_MAX
| HWMON_T_MIN
|
197 HWMON_T_INPUT
| HWMON_T_MAX
| HWMON_T_MIN
|
199 HWMON_T_INPUT
| HWMON_T_MAX
| HWMON_T_MIN
|
201 HWMON_T_INPUT
| HWMON_T_MAX
| HWMON_T_MIN
|
203 HWMON_T_INPUT
| HWMON_T_MAX
| HWMON_T_MIN
|
205 HWMON_T_INPUT
| HWMON_T_MAX
| HWMON_T_MIN
|
207 HWMON_T_INPUT
| HWMON_T_MAX
| HWMON_T_MIN
|
212 static const struct hwmon_ops nvme_hwmon_ops
= {
213 .is_visible
= nvme_hwmon_is_visible
,
214 .read
= nvme_hwmon_read
,
215 .read_string
= nvme_hwmon_read_string
,
216 .write
= nvme_hwmon_write
,
219 static const struct hwmon_chip_info nvme_hwmon_chip_info
= {
220 .ops
= &nvme_hwmon_ops
,
221 .info
= nvme_hwmon_info
,
224 int nvme_hwmon_init(struct nvme_ctrl
*ctrl
)
226 struct device
*dev
= ctrl
->dev
;
227 struct nvme_hwmon_data
*data
;
228 struct device
*hwmon
;
231 data
= devm_kzalloc(dev
, sizeof(*data
), GFP_KERNEL
);
236 mutex_init(&data
->read_lock
);
238 err
= nvme_hwmon_get_smart_log(data
);
240 dev_warn(ctrl
->device
,
241 "Failed to read smart log (error %d)\n", err
);
242 devm_kfree(dev
, data
);
246 hwmon
= devm_hwmon_device_register_with_info(dev
, "nvme", data
,
247 &nvme_hwmon_chip_info
,
250 dev_warn(dev
, "Failed to instantiate hwmon device\n");
251 devm_kfree(dev
, data
);