1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * NVM Express hardware monitoring support 4 * Copyright (c) 2019, Guenter Roeck 5 */ 6 7 #include <linux/hwmon.h> 8 #include <linux/units.h> 9 #include <asm/unaligned.h> 10 11 #include "nvme.h" 12 13 struct nvme_hwmon_data { 14 struct nvme_ctrl *ctrl; 15 struct nvme_smart_log *log; 16 struct mutex read_lock; 17 }; 18 19 static int nvme_get_temp_thresh(struct nvme_ctrl *ctrl, int sensor, bool under, 20 long *temp) 21 { 22 unsigned int threshold = sensor << NVME_TEMP_THRESH_SELECT_SHIFT; 23 u32 status; 24 int ret; 25 26 if (under) 27 threshold |= NVME_TEMP_THRESH_TYPE_UNDER; 28 29 ret = nvme_get_features(ctrl, NVME_FEAT_TEMP_THRESH, threshold, NULL, 0, 30 &status); 31 if (ret > 0) 32 return -EIO; 33 if (ret < 0) 34 return ret; 35 *temp = kelvin_to_millicelsius(status & NVME_TEMP_THRESH_MASK); 36 37 return 0; 38 } 39 40 static int nvme_set_temp_thresh(struct nvme_ctrl *ctrl, int sensor, bool under, 41 long temp) 42 { 43 unsigned int threshold = sensor << NVME_TEMP_THRESH_SELECT_SHIFT; 44 int ret; 45 46 temp = millicelsius_to_kelvin(temp); 47 threshold |= clamp_val(temp, 0, NVME_TEMP_THRESH_MASK); 48 49 if (under) 50 threshold |= NVME_TEMP_THRESH_TYPE_UNDER; 51 52 ret = nvme_set_features(ctrl, NVME_FEAT_TEMP_THRESH, threshold, NULL, 0, 53 NULL); 54 if (ret > 0) 55 return -EIO; 56 57 return ret; 58 } 59 60 static int nvme_hwmon_get_smart_log(struct nvme_hwmon_data *data) 61 { 62 return nvme_get_log(data->ctrl, NVME_NSID_ALL, NVME_LOG_SMART, 0, 63 NVME_CSI_NVM, data->log, sizeof(*data->log), 0); 64 } 65 66 static int nvme_hwmon_read(struct device *dev, enum hwmon_sensor_types type, 67 u32 attr, int channel, long *val) 68 { 69 struct nvme_hwmon_data *data = dev_get_drvdata(dev); 70 struct nvme_smart_log *log = data->log; 71 int temp; 72 int err; 73 74 /* 75 * First handle attributes which don't require us to read 76 * the smart log. 77 */ 78 switch (attr) { 79 case hwmon_temp_max: 80 return nvme_get_temp_thresh(data->ctrl, channel, false, val); 81 case hwmon_temp_min: 82 return nvme_get_temp_thresh(data->ctrl, channel, true, val); 83 case hwmon_temp_crit: 84 *val = kelvin_to_millicelsius(data->ctrl->cctemp); 85 return 0; 86 default: 87 break; 88 } 89 90 mutex_lock(&data->read_lock); 91 err = nvme_hwmon_get_smart_log(data); 92 if (err) 93 goto unlock; 94 95 switch (attr) { 96 case hwmon_temp_input: 97 if (!channel) 98 temp = get_unaligned_le16(log->temperature); 99 else 100 temp = le16_to_cpu(log->temp_sensor[channel - 1]); 101 *val = kelvin_to_millicelsius(temp); 102 break; 103 case hwmon_temp_alarm: 104 *val = !!(log->critical_warning & NVME_SMART_CRIT_TEMPERATURE); 105 break; 106 default: 107 err = -EOPNOTSUPP; 108 break; 109 } 110 unlock: 111 mutex_unlock(&data->read_lock); 112 return err; 113 } 114 115 static int nvme_hwmon_write(struct device *dev, enum hwmon_sensor_types type, 116 u32 attr, int channel, long val) 117 { 118 struct nvme_hwmon_data *data = dev_get_drvdata(dev); 119 120 switch (attr) { 121 case hwmon_temp_max: 122 return nvme_set_temp_thresh(data->ctrl, channel, false, val); 123 case hwmon_temp_min: 124 return nvme_set_temp_thresh(data->ctrl, channel, true, val); 125 default: 126 break; 127 } 128 129 return -EOPNOTSUPP; 130 } 131 132 static const char * const nvme_hwmon_sensor_names[] = { 133 "Composite", 134 "Sensor 1", 135 "Sensor 2", 136 "Sensor 3", 137 "Sensor 4", 138 "Sensor 5", 139 "Sensor 6", 140 "Sensor 7", 141 "Sensor 8", 142 }; 143 144 static int nvme_hwmon_read_string(struct device *dev, 145 enum hwmon_sensor_types type, u32 attr, 146 int channel, const char **str) 147 { 148 *str = nvme_hwmon_sensor_names[channel]; 149 return 0; 150 } 151 152 static umode_t nvme_hwmon_is_visible(const void *_data, 153 enum hwmon_sensor_types type, 154 u32 attr, int channel) 155 { 156 const struct nvme_hwmon_data *data = _data; 157 158 switch (attr) { 159 case hwmon_temp_crit: 160 if (!channel && data->ctrl->cctemp) 161 return 0444; 162 break; 163 case hwmon_temp_max: 164 case hwmon_temp_min: 165 if ((!channel && data->ctrl->wctemp) || 166 (channel && data->log->temp_sensor[channel - 1] && 167 !(data->ctrl->quirks & 168 NVME_QUIRK_NO_SECONDARY_TEMP_THRESH))) { 169 if (data->ctrl->quirks & 170 NVME_QUIRK_NO_TEMP_THRESH_CHANGE) 171 return 0444; 172 return 0644; 173 } 174 break; 175 case hwmon_temp_alarm: 176 if (!channel) 177 return 0444; 178 break; 179 case hwmon_temp_input: 180 case hwmon_temp_label: 181 if (!channel || data->log->temp_sensor[channel - 1]) 182 return 0444; 183 break; 184 default: 185 break; 186 } 187 return 0; 188 } 189 190 static const struct hwmon_channel_info *const nvme_hwmon_info[] = { 191 HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), 192 HWMON_CHANNEL_INFO(temp, 193 HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN | 194 HWMON_T_CRIT | HWMON_T_LABEL | HWMON_T_ALARM, 195 HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN | 196 HWMON_T_LABEL, 197 HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN | 198 HWMON_T_LABEL, 199 HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN | 200 HWMON_T_LABEL, 201 HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN | 202 HWMON_T_LABEL, 203 HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN | 204 HWMON_T_LABEL, 205 HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN | 206 HWMON_T_LABEL, 207 HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN | 208 HWMON_T_LABEL, 209 HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN | 210 HWMON_T_LABEL), 211 NULL 212 }; 213 214 static const struct hwmon_ops nvme_hwmon_ops = { 215 .is_visible = nvme_hwmon_is_visible, 216 .read = nvme_hwmon_read, 217 .read_string = nvme_hwmon_read_string, 218 .write = nvme_hwmon_write, 219 }; 220 221 static const struct hwmon_chip_info nvme_hwmon_chip_info = { 222 .ops = &nvme_hwmon_ops, 223 .info = nvme_hwmon_info, 224 }; 225 226 int nvme_hwmon_init(struct nvme_ctrl *ctrl) 227 { 228 struct device *dev = ctrl->device; 229 struct nvme_hwmon_data *data; 230 struct device *hwmon; 231 int err; 232 233 data = kzalloc(sizeof(*data), GFP_KERNEL); 234 if (!data) 235 return -ENOMEM; 236 237 data->log = kzalloc(sizeof(*data->log), GFP_KERNEL); 238 if (!data->log) { 239 err = -ENOMEM; 240 goto err_free_data; 241 } 242 243 data->ctrl = ctrl; 244 mutex_init(&data->read_lock); 245 246 err = nvme_hwmon_get_smart_log(data); 247 if (err) { 248 dev_warn(dev, "Failed to read smart log (error %d)\n", err); 249 goto err_free_log; 250 } 251 252 hwmon = hwmon_device_register_with_info(dev, "nvme", 253 data, &nvme_hwmon_chip_info, 254 NULL); 255 if (IS_ERR(hwmon)) { 256 dev_warn(dev, "Failed to instantiate hwmon device\n"); 257 err = PTR_ERR(hwmon); 258 goto err_free_log; 259 } 260 ctrl->hwmon_device = hwmon; 261 return 0; 262 263 err_free_log: 264 kfree(data->log); 265 err_free_data: 266 kfree(data); 267 return err; 268 } 269 270 void nvme_hwmon_exit(struct nvme_ctrl *ctrl) 271 { 272 if (ctrl->hwmon_device) { 273 struct nvme_hwmon_data *data = 274 dev_get_drvdata(ctrl->hwmon_device); 275 276 hwmon_device_unregister(ctrl->hwmon_device); 277 ctrl->hwmon_device = NULL; 278 kfree(data->log); 279 kfree(data); 280 } 281 } 282